使用 QLinkedList 循环浏览不同的 window 屏幕

Using QLinkedList to cycle through different window screens

对于我的 Qt 应用程序,我正在尝试使用 QLinkedList,用户可以循环浏览用户创建的新 window 屏幕。 windows 是在用户单击 MainWindow 上的 "New Window" 按钮时动态创建的,MainWindow 对象被添加到 QLinkedList

我正在尝试使用 QLinkedListIterator 作为后退和前进按钮指向上一个屏幕和下一个屏幕。到目前为止,它适用于“前进”按钮,但对于“后退”按钮,它会崩溃,如果我在第一个屏幕上单击“后退”,它也会崩溃。

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>
#include <QLabel>
#include <QTextEdit>

#include <QLinkedList>
#include <QLinkedListIterator>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QLinkedList<MainWindow*> window_list;

private:
    Ui::MainWindow *ui;

    QPushButton *button;

    MainWindow* new_window;

    // Add new Window
    void input_new_window();

    // Forward and back buttons
    void input_back_button();
    void input_forward_button();

    void go_back();
    void go_forward();

    void addWindow();
};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->resize(800, 400);

    //---------------------------
    // Show buttons
    //----------------------------
    this->input_back_button();
    this->input_forward_button();
    this->input_new_window();
}

MainWindow::~MainWindow()
{
    delete ui;
}

// Add Window to the front of the list
void MainWindow::addWindow()
{
    // Create new Window Object
    new_window = new MainWindow();

    // Add the New Window to the list
    window_list.append(new_window);

    // Display the New Window
    new_window->show();
}


void MainWindow::go_back()
{
    // Go back to previous window in the linkedlist
    QMutableLinkedListIterator<MainWindow*> i(window_list);

    if(i.hasPrevious())
    {
        new_window->show();
        this->hide();
    }
}


void MainWindow::go_forward()
{
    // Go forward to next window in the linkedlist
    QMutableLinkedListIterator<MainWindow*> i(window_list);

    if(i.hasNext())
    {
        new_window->show();
        this->hide();
    }
}


//----------------------------------------------------------
// Open New Window
//----------------------------------------------------------
void MainWindow::input_new_window()
{
    button = new QPushButton("New Window", this);
    button->setGeometry(QRect(QPoint(10, 30), QSize(200, 50)));
    button->show();
    QObject::connect(button, &QPushButton::pressed, this, &MainWindow::addWindow);
}


//--------------------------------------------------------
// Going forward and back with windows
//--------------------------------------------------------
void MainWindow::input_back_button()
{
    button = new QPushButton("Back", this);
    button->setGeometry(QRect(QPoint(10, 340), QSize(200, 50)));
    button->show();

    // Link back button with going back a screen
    QObject::connect(button, &QPushButton::pressed, this, &MainWindow::go_back);
}


void MainWindow::input_forward_button()
{
    button = new QPushButton("Forward", this);
    button->setGeometry(QRect(QPoint(580, 340), QSize(200, 50)));
    button->show();

    // Link forward button with going forward a screen
    QObject::connect(button, &QPushButton::pressed, this, &MainWindow::go_forward);
}

您正在使用 windows 的不同列表:您添加的每个新 window 都有自己的列表,因此循环实际上是不可能的。此外,new_window 变量作为成员不是必需的,我认为它给您造成了一些混乱。

它对forward起作用的原因是因为new_window已经持有了下一个window(你在调用addWindow方法时分配了它,所以它实际上是下一个 window)。另一方面,后面也使用了new_window),所以不会像预期的那样工作。

要解决您的问题,请尝试使用 windows 的共享列表,可能是全局列表,或者在构造每个 window.

时传递它

下面的解决方案不是最优雅的,可能有竞争条件,但可以说明我的观点。它使用 windows 的全局列表:每次你想向前或向后移动时,它都会搜索当前的 window 并在列表上循环。另外,我删除了 new_window 成员 ;)

在头文件中

class MainWindow ... {
public:
    static void addWindowToList(MainWindow* w);
}

在 .cpp 文件中

// ...
#include <cassert>

namespace {
    QLinkedList<MainWindow*> window_list; // global list
}

// ...

void MainWindow::addWindowToList(MainWindow* w)
{
    window_list.append(w);
}

void MainWindow::addWindow()
{
    addWindowToList(new MainWindow());
    go_forward(); // shows new window
}

void MainWindow::go_back()
{
    if (window_list.count() == 1) return; // no other windows

    if (window_list.first() == this) { // has to go the last one
        window_list.back()->show();
    } else {
        auto it = std::find(window_list.begin(), window_list.end(), this);
        assert(it != window_list.end()); // should be in the list
        (*(--it))->show();
    }

    hide();
}

void MainWindow::go_forward()
{
    if (window_list.count() == 1) return; // no other windows

    if (window_list.back() == this) { // has to go to the first one
        window_list.first()->show();
    } else {
        auto it = std::find(window_list.begin(), window_list.end(), this);
        assert(it != window_list.end()); // should be in the list
        (*(++it))->show();
    }

    hide();
}

// ...

现在,您还应该将第一个 window 添加到列表中。可能您正在使用默认的 Qt 模板,例如:

int main(int argc, char* argv[]) {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

不是在堆栈上创建对象,而是动态创建对象并将其添加到列表中:

int main(int argc, char* argv[]) {
    QApplication a(argc, argv);
    auto w = new MainWindow();
    MainWindow::addWindowToList(w);
    w->show();
    return a.exec();
}

  • it 迭代器实际上是 QLinkedList::iterator 和类似 STL 的迭代器,而不是类似 Java 的迭代器。没什么大不了的,只是我对第一个更熟悉。

  • 由于我现在无法访问我的开发环境,因此无法测试代码,所以请原谅我的任何错字或编译错误。


改进

  • 无需手动使用 addWindowToList 方法,您可以在 MainWindow 构造函数中执行此操作 (addWindowToList(this)),因此您只需创建它们,它们将自动添加.
  • 代码没有显示任何关于销毁 windows 的信息。您应该注意在关闭/销毁时将它们从列表中删除,否则在循环 windows 时会发生崩溃。以与构造函数类似的方式,您可以在析构函数上执行此操作并从列表中删除 window。