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

Using QLinkedList to cycle through different window screens

本文关键字:窗口 屏幕 QLinkedList 循环 浏览 使用      更新时间:2023-10-16

对于我的Qt应用程序,我正在尝试使用用户可以循环浏览用户创建的新窗口屏幕的QLinkedList。当用户单击MainWindow对象添加到QLinkedListMainWindow上的"新建窗口"按钮时,将动态创建窗口。

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

主窗口.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

主窗口.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);
}

您正在使用不同的窗口列表:您添加的每个新窗口都包含自己的列表,因此实际上无法循环。此外,new_window变量作为成员不是必需的,我认为这会给您带来一些混乱。

它适用于转发的原因是new_window已经持有下一个窗口(您在调用addWindow方法时分配了它,因此它实际上是下一个窗口)。另一方面,背面也正在使用new_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();
}
// ...

现在,您还应该将第一个窗口添加到列表中。可能您正在使用默认的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)),因此您只需创建它们,它们将自动添加。
  • 该代码不显示有关销毁窗口的任何内容。您应该注意在关闭/销毁时将它们从列表中删除,否则在循环窗户时会出现崩溃。与构造函数类似的方式,您可以在析构函数上执行此操作并从列表中删除窗口。