When moved a QDialog to another monitor and close it, the dialog will be blank after reopened - qt

Env: Win10+Qt5.12.3(msvc)
code:
pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = test
TEMPLATE = app
SOURCES += \
dialog.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
dialog.h \
mainwindow.h
FORMS += \
dialog.ui \
mainwindow.ui
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDialog>
#include "dialog.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void slot_btn_clicked();
private:
Ui::MainWindow *ui;
Dialog *dialog;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
dialog = new Dialog(this);
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(slot_btn_clicked()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slot_btn_clicked()
{
dialog->exec();
}
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QCloseEvent>
#include <QShowEvent>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
protected:
void closeEvent(QCloseEvent *e);
public:
explicit Dialog(QWidget *parent = nullptr);
~Dialog();
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
QVBoxLayout *layout = new QVBoxLayout(this);
QLabel *label = new QLabel(this);
label->setText("this is a label");
layout->addWidget(label);
QPushButton *btnaccept= new QPushButton(this);
btnaccept->setText("accept");
connect(btnaccept, &QPushButton::clicked, this, [=](){accept();});
layout->addWidget(btnaccept);
QPushButton *btnclose= new QPushButton(this);
btnclose->setText("close");
connect(btnclose, &QPushButton::clicked, this, [=](){close();});
layout->addWidget(btnclose);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::closeEvent(QCloseEvent *e)
{
qDebug() << __FUNCTION__;
QDialog::closeEvent(e);
//e->ignore(); // if ignored close event, working well.
//accept();
}
demo code pack
Video presentation
I found that a method of closing QDialog will cause this situation: close button in title bar(top-right corner of the dialog), if closing it by reject(), accept(), close() everything is working correctly.
There is another question which is similar with mine, but I think the answer (resize the dialog manually) is not perfect, is there any another solution?

Related

How to use QTimer to view a image sequence?

In the program, I am trying to create a image player using QT. When I click a button in the UI, the program will create a image slideshow with a 2s pause. I tried to use the QTimer to such things, but failed to do so. Hence, I want to ask how to achieve my purpose by using QTimer.
Let me describe the flow of my program. When the user click a button in the main window, the sub-window showpic will be opened and then start showing each image for a pause of 2s in its qgraphsview. The images filepath are stored in the "QStringlist filenames".
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
#include "showpic.h"
#include <QBasicTimer>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void display(const QString & , ShowPic* );
private slots:
void tick();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QFileSystemModel *model;
QString filesPath;
ShowPic *showpic;
QStringList filenames;
QStringList::const_iterator m_imageIt;
QTimer m_timer;
};
#endif // MAINWINDOW_H
showpic.h
#ifndef SHOWPIC_H
#define SHOWPIC_H
#include <QWidget>
namespace Ui {
class ShowPic;
}
class ShowPic : public QWidget
{
Q_OBJECT
public:
explicit ShowPic(QWidget *parent = 0);
~ShowPic();
private:
Ui::ShowPic *ui;
public:
void addPixmap(const QPixmap &pixmap);
};
#endif // SHOWPIC_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QFileDialog>
#include<QFileSystemModel>
#include<QStringList>
#include <QTreeView>
#include <QGraphicsScene>
#include <QTime>
#include <QThread>
#include <QDebug>
#include <iostream>
#include <QTimer>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
filenames.append("C:\\test\\image.jpg");
filenames.append("C:\\test\\apple.jpg");
filenames.append("C:\\test\\orange.jpg");
filenames.append("C:\\test\\lemon.jpg");
filenames.append("C:\\test\\grape.jpg");
m_imageIt = filenames.begin();
m_timer.setInterval(5000);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::display(const QString & filename, ShowPic* showpic) {
showpic->addPixmap(filename);
}
void MainWindow::tick(){
showpic = new ShowPic();
showpic->show();
display(*m_imageIt, showpic);
m_imageIt ++;
}
/*
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId()) tick();
}*/
void MainWindow::on_pushButton_clicked()
{
/*showpic = new ShowPic();
QPixmap pixmap("C:\\test\\image.jpg");
showpic->addPixmap(pixmap);
showpic->show();*/
m_timer.start();
}
showpic.cpp
#include "showpic.h"
#include "ui_showpic.h"
#include <QThread>
ShowPic::ShowPic(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowPic)
{
ui->setupUi(this);
ui->graphicsView->setScene(new QGraphicsScene);
}
ShowPic::~ShowPic()
{
delete ui;
}
void ShowPic::addPixmap(const QPixmap &pixmap){
ui->graphicsView->scene()->addPixmap(pixmap);
}
The compiling message error:
The error has nothing to do with the timer, it is because you forgot to declare display(), tick(), and timerEvent() as part of the MainWindow:: class, so they cannot access MainWindow members.
The timer should be even easier to use than your code. First I recommend you use a QTimer instead of QBasicTimer. Then you can simply connect to its timeout() signal.
mainwindow.h
#include <QTimer>
QTimer m_timer;
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
...
m_imageIt = filenames.begin();
m_timer.setInterval(5000);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
}
void MainWindow::on_pushButton_clicked()
{
m_timer.start();
}
You do not need timerEvent() function at all.

Drag and drop issue in Qt

I overload dragEnterEvent() and dropEvent() in my MainWindow class, and call setAcceptDrops() in the constructor. While the running, I drag a .txt file in to the texteditor, but it's not showing the content of that .txt. Instead, it's show the path of that .txt. Please somebody help where I did wrong. Thanks.
//Header
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Blockquote
//Source
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDragEnterEvent>
#include <QUrl>
#include <QFile>
#include <QTextStream>
#include <QMimeData>
#include <QList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setAcceptDrops(true);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event){
if(event->mimeData()->hasUrls())
event->acceptProposedAction();
else event->ignore();
}
void MainWindow::dropEvent(QDropEvent *event){
const QMimeData *mimeData = event->mimeData();
if(mimeData->hasUrls()){
QList<QUrl> urlList = mimeData->urls();
QString fileName = urlList.at(0).toLocalFile();
if(! fileName.isEmpty()){
QFile file(fileName);
if(!file.open(QIODevice::ReadOnly))return;
QTextStream in(&file);
ui->textEdit->setText(in.readAll());
}
}
}
You see this behavior because dropping is enabled on QTextEdit and the event is consumed there. (By default TextEdit drop copies filename into text area.)
In your constructor disable dropping on TextEdit by using
ui->textEdit->setAcceptDrops(false)
and then the event will be handled by the dropEvent method in MainWindow

QScrollArea and QVBoxLayout issues with dynamically added widgets

Im running into a weird issue with dynamically added widgets to a QVBoxLayout contained inside a QScrollArea. If I add the widgets it works as expected, however after all widgets are removed, there are still some artifacts on the screen. See screenshot bellow:
See the code bellow:
ui_mainwindow.h
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.2.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QScrollArea>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QWidget *centralWidget;
QVBoxLayout *verticalLayout_2;
QScrollArea *scrollArea;
QWidget *scrollAreaWidgetContents;
QHBoxLayout *horizontalLayout_2;
QVBoxLayout *verticalLayout;
QPushButton *pushButton;
QPushButton *pushButton_2;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QStringLiteral("MainWindow"));
MainWindow->resize(600, 396);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
verticalLayout_2 = new QVBoxLayout(centralWidget);
verticalLayout_2->setSpacing(6);
verticalLayout_2->setContentsMargins(11, 11, 11, 11);
verticalLayout_2->setObjectName(QStringLiteral("verticalLayout_2"));
scrollArea = new QScrollArea(centralWidget);
scrollArea->setObjectName(QStringLiteral("scrollArea"));
scrollArea->setWidgetResizable(true);
scrollAreaWidgetContents = new QWidget();
scrollAreaWidgetContents->setObjectName(QStringLiteral("scrollAreaWidgetContents"));
scrollAreaWidgetContents->setGeometry(QRect(0, 0, 574, 246));
horizontalLayout_2 = new QHBoxLayout(scrollAreaWidgetContents);
horizontalLayout_2->setSpacing(6);
horizontalLayout_2->setContentsMargins(11, 11, 11, 11);
horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2"));
verticalLayout = new QVBoxLayout();
verticalLayout->setSpacing(6);
verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
horizontalLayout_2->addLayout(verticalLayout);
scrollArea->setWidget(scrollAreaWidgetContents);
verticalLayout_2->addWidget(scrollArea);
pushButton = new QPushButton(centralWidget);
pushButton->setObjectName(QStringLiteral("pushButton"));
verticalLayout_2->addWidget(pushButton);
pushButton_2 = new QPushButton(centralWidget);
pushButton_2->setObjectName(QStringLiteral("pushButton_2"));
verticalLayout_2->addWidget(pushButton_2);
MainWindow->setCentralWidget(centralWidget);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QStringLiteral("menuBar"));
menuBar->setGeometry(QRect(0, 0, 600, 22));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QStringLiteral("statusBar"));
MainWindow->setStatusBar(statusBar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
pushButton->setText(QApplication::translate("MainWindow", "add one", 0));
pushButton_2->setText(QApplication::translate("MainWindow", "remove one", 0));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
ui->verticalLayout->addWidget(new QLabel("This is a label", this));
qDebug() << "Labels count: " << ui->verticalLayout->count();
}
void MainWindow::on_pushButton_2_clicked()
{
delete ui->verticalLayout->takeAt(0);
qDebug() << "Labels count: " << ui->verticalLayout->count();
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
It seems like I also have to remove the QLayoutItem AND the Widget, just removing the widget or the QLayoutItem (which I did try) doesn't work, both have to be removed, like so:
QLayoutItem *child = ui->verticalLayout->takeAt(0);
if (child)
{
delete child->widget();
delete child;
}

Need help connecting signal from thread to slot in GUI

mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void disableStartButton();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QtCore>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = 0);
void doSetup(QThread &cThread);
signals:
void disableStartButton();
public slots:
void doWork();
};
#endif // MYOBJECT_H
main.cpp:
#include "mainwindow.h"
#include "myobject.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QThread cThread;
MyObject cObject;
cObject.doSetup(cThread);
cObject.moveToThread(&cThread);
return a.exec();
}
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::disableStartButton() {
ui->pushButton->setEnabled(false);
}
myobject.h:
#include "myobject.h"
#include <QDebug>
MyObject::MyObject(QObject *parent) :
QObject(parent)
{
}
void MyObject::doSetup(QThread &cThread)
{
connect(&cThread, SIGNAL(started()), this, SLOT(doWork()));
connect(ui->pushButton, SIGNAL(clicked()), &cThread, SLOT(start())); // (1)
connect(this, SIGNAL(disableStartButton()), ui, SLOT(disableStartButton())); // (2)
}
void MyObject::doWork()
{
emit disableStartButton();
qDebug() << "1";
}
I'm trying to do two things.
(1): As soon pushButton is clicked, I want cThread to start.
(2): As soon as cThread starts, it does: emit disableStartButton();. I want to connect disableStartButton() to disableStartButton() in mainwindow.cpp.
For (1), I get this error:
myobject.cpp:12: error: C2065: 'ui' : undeclared identifier
Of course, there ui is undefined. You try to connect ui->pushButton
connect(ui->pushButton, SIGNAL(clicked()), &cThread, SLOT(start())); // (1)
in file myobject.cpp, when your ui declared only in mainwindow.cpp
You have to connect pushbutton to your thread within mainwindow.cpp file, hope that helps
By the way, you should create your objects NOT in main.cpp but, in your case, in mainwindow.cpp, move lines
QThread cThread;
MyObject cObject;
cObject.doSetup(cThread);
cObject.moveToThread(&cThread);
to file mainwindow.cpp in constructor, for example
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
right after ui->setupUi(this);

Qt readAllStandardOutput() causes unexpected program end

When I try to emit readAllStandardOutput() to a QString im getting an unexpected program crash, even if i connvert the QByteStream to a QString, any idea why that is? heres teh source
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QProcess>
#include <QString>
#include "exeprocess.h"
/*main window ---------------------------------------*/
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QProcess *proc;
signals:
void outLog(QString outLogVar); //plug this into the QTextEdit box
public slots:
void logReady(); // plug the QProcess into this
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include <QByteArray>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QProcess *proc = new QProcess; //initialize proc
QStringList arguments;
arguments << "-h";
connect(proc, SIGNAL(readyReadStandardOutput ()), this, SLOT(logReady()));
proc->start("/Applications/Graphics/3Delight-9.0.87/bin/renderdl", arguments);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::logReady(){
QString str = proc->readAllStandardOutput();
emit outLog(str);
}
Thanks!
This line is the problem:
QProcess *proc = new QProcess; //initialize proc
You're shadowing the member variable by reusing that name. When logReady is called, the 'proc' that you call readAllStandardOutput() on is a different (null) pointer and so everything crashes. The fix is simple: replace the above line with
proc = new QProcess;

Resources