Parent and Child Window Communication in Qt - Child Window opens twice - qt

I have two windows, one parent and one child. In parent window, I have a Next button, which onClick()'ed, opens up child window, but in my case two child windows are opening, what is the mistake am doing!?
Here are my codes:
.h files
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <info.h>
#include <QtGui>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void changeEvent(QEvent *e);
private:
Ui::MainWindow *ui;
void setSignals();
private slots:
void process();
};
#endif // MAINWINDOW_H
info.h
#ifndef INFO_H
#define INFO_H
#include <QMainWindow>
namespace Ui {
class info;
}
class info : public QMainWindow {
Q_OBJECT
public:
info(QWidget *parent = 0);
~info();
protected:
void changeEvent(QEvent *e);
private:
Ui::info *ui;
};
#endif // INFO_H
.cpp files
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtGui/QApplication>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setSignals();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void MainWindow::setSignals(){
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(process()));
connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(close()));
}
void MainWindow::process(){
info *i;
i = new info;
this -> hide();
i -> show();
}
info.cpp
#include "info.h"
#include "ui_info.h"
info::info(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::info)
{
ui->setupUi(this);
}
info::~info()
{
delete ui;
}
void info::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

I solved it, here was the problem:
In designer header file i.e., in ui_mainwindow.h, I have:
QObject::connect(pushButton, SIGNAL(clicked()), MainWindow, SLOT(process()));
QObject::connect(pushButton_2, SIGNAL(clicked()), MainWindow, SLOT(close()));
and in the source file i.e., mainwindow.cpp in setSignals(), I have again stated:
void MainWindow::setSignals()
{
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(process()));
connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(close()));
}
So with the two connects, we get two calls to process() , we have to comment anyone to show only one child window. That's it :-)

Related

How to reuse the same window after clicking on other button?

I am trying to create an image viewer with slide show. When the user clicks on the play button, the viewer starts to show images. When the the user clicks on the stop button, the viewer stops to show images. After stopping, when the user clicks on the play button again, the viewer will continue to show the remaining images. My problem is that when the user clicks on the stop button and click on the play button again, I don't know how to reuse the same window created at the beginning to show the remaining images.
Button3 is the play button.
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();
private slots:
void on_pushButton_3_clicked();
void tick();
void on_pushButton_4_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 <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_timer.setInterval(1000);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::tick(){
showpic->addPixmap(*m_imageIt);
m_imageIt ++;
if(m_imageIt == filenames.end()){
m_timer.stop();
m_imageIt = filenames.begin();
}
}
void MainWindow::on_pushButton_3_clicked() //click on the play button
{
if(!filenames.isEmpty()){ // initial click
showpic = new ShowPic();
m_timer.start();
showpic->setWindowState(Qt::WindowMaximized);
showpic->show();
} else if( ) { // click on the play button again,
m_timer.start(); //???
showpic->setWindowState(Qt::WindowMaximized); //???
showpic->show(); //???
}
}
void MainWindow::on_pushButton_4_clicked() // click on the stop button
{
m_timer.stop();
}
showpic.cpp
#include "showpic.h"
#include "ui_showpic.h"
ShowPic::ShowPic(QWidget *parent) :
QWidget(parent),
ui(new Ui::ShowPic)
{
ui->setupUi(this);
ui->graphicsView->setScene(new QGraphicsScene);
ui->horizontalLayout->addWidget(ui->graphicsView);
this->setLayout(ui->horizontalLayout);
}
ShowPic::~ShowPic()
{
delete ui;
}
void ShowPic::addPixmap(const QPixmap &pixmap){
ui->horizontalLayout->addWidget(ui->graphicsView);
this->setLayout(ui->horizontalLayout);
ui->graphicsView->setScene(new QGraphicsScene);
ui->graphicsView->scene()->addPixmap(pixmap);
ui->graphicsView->fitInView(ui->graphicsView->scene()->itemsBoundingRect() ,Qt::KeepAspectRatio);
}
Else part of on_pushButton_3_clicked won't run in any case because filenames is being filled when MainWindow created. In your code, you're creating new showpic in every click.
Firstly, set showpic to NULL in constructor of MainWindow;
showpic = NULL;
And change on_pushButton_3_clicked method like this;
void MainWindow::on_pushButton_3_clicked() //click on the play button
{
if(showpic == NULL){
showpic = new ShowPic();
}
if(!showpic->isVisible()){
showpic->setWindowState(Qt::WindowMaximized);
showpic->show();
}
m_timer.start();
}
Lastly, i don't have QT now, so my answer may contains typo/syntax error.
This works for me. I tested the scene clearing method, and it worked fine for me. But here I decided to just store the pointer to the QGraphicsPixmapItem as a member variable, and just set a new pixmap to it, instead of clearing the scene constantly. Seems more elegant like this to me.
#include <QtWidgets>
class SlideView : public QWidget
{
Q_OBJECT
public:
SlideView(QWidget *parent = nullptr) : QWidget(parent)
{
setLayout(new QHBoxLayout);
layout()->addWidget(&view);
view.setScene(new QGraphicsScene(this));
pixmap_item = new QGraphicsPixmapItem;
view.scene()->addItem(pixmap_item);
}
void setPixmap(const QPixmap &pixmap)
{
pixmap_item->setPixmap(pixmap);
view.fitInView(view.scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
}
private:
QGraphicsView view;
QGraphicsPixmapItem *pixmap_item = nullptr;
};
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = nullptr) : QWidget(parent)
{
slide_iterator = slides.begin();
setLayout(new QHBoxLayout);
QPushButton *play_button = new QPushButton("Play");
QPushButton *stop_button = new QPushButton("Stop");
layout()->addWidget(play_button);
layout()->addWidget(stop_button);
connect(play_button, &QPushButton::clicked, this, &MainWidget::play);
connect(stop_button, &QPushButton::clicked, this, &MainWidget::stop);
connect(&timer, &QTimer::timeout, this, &MainWidget::showNextSlide);
}
public slots:
void play() {timer.start(1000); view.showMaximized(); view.activateWindow();}
void stop() {timer.stop();}
void showNextSlide()
{
QPixmap pixmap(*slide_iterator);
view.setPixmap(pixmap);
slide_iterator++;
if(slide_iterator == slides.end())
slide_iterator = slides.begin();
}
private:
QTimer timer;
QStringList slides{"one.png", "two.png", "three.png"};
QStringList::const_iterator slide_iterator;
SlideView view;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}
#include "main.moc"

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

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);

failure to initialize multiple windows using qt

I've been struggling with the problem of initializing of multiple forms in Qt under Windows (the version is 5.0.1 but I don't reckon this to matter much). Long story short, my application contains of 2 forms the one of which is supposed to be called on clicking the button on the another one.
The code runs as follows:
1) main.cpp:
#include "main.h"
#include <QApplication>
FmNewWord fmNewWord;
MainWindow w;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
w.show();
return a.exec();
}
2) main.h:
#ifndef MAIN_H
#define MAIN_H
#include "mainwindow.h"
#include "fmnewword.h"
extern FmNewWord fmNewWord;
extern MainWindow w;
#endif // MAIN_H
3) mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_mainwindow.h"
class MainWindow : public QMainWindow, private Ui::MainWindow
{
Q_OBJECT
signals:
void sgnl_new_word();
public:
explicit MainWindow(QWidget *parent = 0);
protected:
void changeEvent(QEvent *e);
private slots:
void on_commandLinkButton_clicked();
void on_miExit_triggered();
void on_miNewWord_triggered();
};
#endif // MAINWINDOW_H
4) mainwindow.cpp:
#include "main.h"
#include <Windows.h>
extern FmNewWord fmNewWord;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);
}
void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
retranslateUi(this);
break;
default:
break;
}
}
void MainWindow::on_commandLinkButton_clicked()
{
MessageBox(0, 0, 0, 0);
}
void MainWindow::on_miExit_triggered()
{
this->close();
}
void MainWindow::on_miNewWord_triggered()
{
fmNewWord.show();
}
5) fmnewword.cpp:
#include "fmnewword.h"
FmNewWord::FmNewWord(QWidget *parent) :
QMainWindow(parent)
{
setupUi(this); /// here the app crashes with parent == NULL
}
void FmNewWord::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
retranslateUi(this);
break;
default:
break;
}
}
6) fmnewword.h:
#ifndef FMNEWWORD_H
#define FMNEWWORD_H
#include "ui_fmnewword.h"
class FmNewWord : public QMainWindow, private Ui::FmNewWord
{
Q_OBJECT
public:
explicit FmNewWord(QWidget *parent = 0);
protected:
void changeEvent(QEvent *e);
};
#endif // FMNEWWORD_H
The code keeps crashing during inititialization in fmnewword.cpp on the line shown. Could anybody point out the reason? Thanks.
First of all, QApplication must be created before any widgets.
Your code should look llike this:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
And that's how the second form must be created:
class FmNewWord;
class MainWindow : public QMainWindow, private Ui::MainWindow
{
Q_OBJECT
...
private slots:
void on_miNewWord_triggered();
private:
FmNewWord *fmNewWord;
};
void MainWindow::on_miNewWord_triggered()
{
fmNewWord = new FmNewWord;
fmNewWord->show();
}

Resources