I have an application with a few screens that I would like to load on application launch and keep in memory while the program is running. I want to be able to switch between screens on a button click, hiding the current screen while showing the next screen. There is not a direct path through the application, the user may go back and forth through screens in the application. I'm using Qt and new to c++.
The following is skeleton code I would like to get to work (or get advice about a better way to do it). I'm doing it this way in order to avoid memory leaks from creating new instances of the dialogs when moving back and forth through the application a number of times.
When I compile this, I get an error Undefined Reference to 'Screen2' in Screen2->show(); in Dialog1::on_pushButton_clicked() in dialog1.cpp. I tried everything I could to get this to compile without success. Why isn't Screen2 a valid pointer in dialog1.cpp?
I have a Manager which is run from Main and initialises the dialogs.
manager.cpp:
#include "manager.h"
#include "ui_manager.h"
Manager::Manager(QWidget *parent) :
QDialog(parent),
ui(new Ui::Manager)
{
ui->setupUi(this);
Screen1 = new Dialog1(this);
Screen2 = new Dialog2(this);
Screen1->show();
}
Manager::~Manager()
{
delete ui;
}
manager.h:
#ifndef MANAGER_H
#define MANAGER_H
#include <QDialog>
#include "dialog1.h"
#include "dialog2.h"
namespace Ui {
class Manager;
}
class Manager : public QDialog
{
Q_OBJECT
public:
explicit Manager(QWidget *parent = 0);
~Manager();
Dialog1 *Screen1;
Dialog2 *Screen2;
private:
Ui::Manager *ui;
};
#endif // MANAGER_H
dialog1.cpp:
#include "dialog1.h"
#include "ui_dialog1.h"
#include "manager.h"
#include "dialog2.h"
#include <QDebug>
extern Dialog1 *Screen1;
extern Dialog2 *Screen2;
Dialog1::Dialog1(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog1)
{
ui->setupUi(this);
}
Dialog1::~Dialog1()
{
delete ui;
}
void Dialog1::on_pushButton_clicked()
{
Screen2->show();
}
dialog1.h:
#ifndef DIALOG1_H
#define DIALOG1_H
#include <QDialog>
#include "dialog2.h"
class Manager;
namespace Ui {
class Dialog1;
}
class Dialog1 : public QDialog
{
Q_OBJECT
public:
explicit Dialog1(QWidget *parent = 0);
~Dialog1();
private slots:
void on_pushButton_clicked();
private:
Ui::Dialog1 *ui;
};
#endif // DIALOG1_H
dialog2.cpp:
#include "dialog2.h"
#include "ui_dialog2.h"
#include "dialog1.h"
#include "manager.h"
extern Dialog1 *Screen1;
extern Dialog2 *Screen2;
Dialog2::Dialog2(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog2)
{
ui->setupUi(this);
}
Dialog2::~Dialog2()
{
delete ui;
}
void Dialog2::on_pushButton_clicked()
{
Screen1->show();
}
All help appreciated!
Regards,
James
I'll explain you easiest way to get it work.
Make screen1 and screen2 private members of manager class.
Add signal buttonPressed() to both screens.
Emit signal on button press in each dialog.
Add slot to manager class to handle button press in dialogs
connect signals of dialogs to manager slot
Remove this in both dialogs:
extern Dialog1 *Screen1;
extern Dialog2 *Screen2;
You can not access them directly because thee are members of your manager object.
As a result you will be able to add as many screens as you want. Each screen won't know anything about others (you were trying to do so).
Related
Create a simple application in Qt (c ++) to encrypt a text. And I get the error: "Cannot create children for a parent that is in a different thread."
I used threads to update a text edit box in real time while entering text.
I saw other similar topics, but I did not find any solution that I could adapt to myself.
Can you please suggest me how I can solve it?
.h file
#ifndef GENERATORSHACODE_H
#define GENERATORSHACODE_H
#include <QMainWindow>
#include <thread>
QT_BEGIN_NAMESPACE
namespace Ui { class GeneratorShaCode; }
QT_END_NAMESPACE
class GeneratorShaCode : public QMainWindow
{
Q_OBJECT
public:
GeneratorShaCode(QWidget *parent = nullptr);
~GeneratorShaCode();
QString Sha512Generator(QString);
void updateOutputEditText();
std::thread GenerateCode;
private:
Ui::GeneratorShaCode *ui;
};
#endif // GENERATORSHACODE_H
.cpp file
#include "generatorshacode.h"
#include "ui_generatorshacode.h"
#include <windows.h>
#include "sha512.h"
#include <string>
#include <QtDebug>
GeneratorShaCode::GeneratorShaCode(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::GeneratorShaCode)
{
ui->setupUi(this);
GenerateCode = std::thread(&GeneratorShaCode::updateOutputEditText, this);
GenerateCode.detach();
}
GeneratorShaCode::~GeneratorShaCode()
{
delete ui;
}
QString GeneratorShaCode::Sha512Generator(QString Qstr)
{
return QString::fromStdString(sha512(Qstr.toStdString()));
}
void GeneratorShaCode::updateOutputEditText()
{
while(true)
{
ui->textEdit_Output->setText(Sha512Generator(ui->textEdit_Input->toPlainText()));
}
}
GUI thread is the main thread. You can't operate any ui controls directly within a sub thread. Usually you should use signals/slots between GUI thread and sub thread.
i'm trying to change the label text of Class A via Class B using Qt but i can't get it working, here's my codes:
Class A:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "loldata.h"
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
LoLData *lold = new LoLData();
QObject::connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(updateData()));
QObject::connect(lold, SIGNAL(updatePlayerID(QString)), ui->label, SLOT(setText(QString)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::updateData()
{
LoLData summoner;
summoner.getSummonerData("Snylerr");
}
Class A: (.h)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QObject>
#include <string>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void updateData();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Class B:
#include "loldata.h"
#include "mainwindow.h"
using namespace std;
int LoLData::getSummonerData(QString playerName)
{
emit updatePlayerID("playerName");
return 0;
}
Class B: (.h)
#ifndef DEF_LOLDATA
#define DEF_LOLDATA
#include <QApplication>
#include <QObject>
#include <string>
class LoLData : public QObject
{
Q_OBJECT
public:
int getSummonerData(QString playerName);
signals:
void updatePlayerID(QString playerName);
private:
};
#endif
You can see that i tried to use slots and signals but the text of the label is not changing, i saw a lot of examples on internet but i can't get them working
Thanks for your reply.
You are creating a new instance of LoLData here:
void MainWindow::updateData()
{
LoLData summoner;
summoner.getSummonerData("Snylerr");
}
This instance of LoLData named summoner is not connected to your label's setText slot.
LoLData *lold = new LoLData(); - this instance of LolData is connected to you label's setText slot.
What should yo do?
It depends on what you want to accomplish:
either connect your summoner instance to the label by inserting a QObject::connect(&summoner...) inside yourupdateData` method;
or you don't instantiate a new LolData variable and use lold inside your updateData function:
void MainWindow::updateData()
{
lold->getSummonerData("Snylerr");
}
Also in this case you have to put lold as a member variable.
In your MainWindow constructor, you connect your lold object to the setText slot.
But in updateData, you use an other object (summoner) which is not connect to anything. So when you use getSummonerData on summoner, the signal updatePlayerID is emitted nut they is no slot connected to it.
I have a QT application and I'm trying to have a button in one of my windows open another window.
The way I have done my window objects so far in the main is like this:
Website control;
control.show();
This displays my first window fine and if I declare my other window in a similar way that also displays at runtime, although this is not what I want
Then in a separate header file:
class Website: public QWidget, public Ui::Website
{
public:
Website();
}
Then in the corresponding Cpp file I have:
Website::Website()
{
setupUi(this);
}
Now all this works and have added a custom slot so that when I click a button it triggers a slot in my other cpp file. The issue is I'm not sure how to show my other window as I declare them in my main so can't access them to do .show()?
Any help would be appreciated, I'm fairly new to C++ and QT
It's not clear to me what you want to do. But i might understand your struggle as I had one myself the first time approaching this framework.
So let's say you have a MainWindow class that controls the main Window view. Than you want to create a second window controlled by Website class.
You then want to connect the two classes so that when you click a button on the Website window something happens in the MainWindow.
I made a simple example for you that is also on GitHub:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "website.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void changeText();
private slots:
void on_openButton_clicked();
private:
Ui::MainWindow *ui;
//You want to keep a pointer to a new Website window
Website* webWindow;
};
#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);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::changeText()
{
ui->text->setText("New Text");
delete webWindow;
}
void MainWindow::on_openButton_clicked()
{
webWindow = new Website();
QObject::connect(webWindow, SIGNAL(buttonPressed()), this, SLOT(changeText()));
webWindow->show();
}
website.h
#ifndef WEBSITE_H
#define WEBSITE_H
#include <QDialog>
namespace Ui {
class Website;
}
class Website : public QDialog
{
Q_OBJECT
public:
explicit Website(QWidget *parent = 0);
~Website();
signals:
void buttonPressed();
private slots:
void on_changeButton_clicked();
private:
Ui::Website *ui;
};
#endif // WEBSITE_H
website.cpp
#include "website.h"
#include "ui_website.h"
Website::Website(QWidget *parent) :
QDialog(parent),
ui(new Ui::Website)
{
ui->setupUi(this);
}
Website::~Website()
{
delete ui;
}
void Website::on_changeButton_clicked()
{
emit buttonPressed();
}
Project composed:
SOURCES += main.cpp\
mainwindow.cpp \
website.cpp
HEADERS += mainwindow.h \
website.h
FORMS += mainwindow.ui \
website.ui
Consider the Uis to be composed:
Main Window: a label called "text" and a button called "openButton"
Website Window: a button called "changeButton"
So the keypoints are the connections between signals and slots and the management of windows pointers or references.
I have a Qt GUI application that opens a dialog when I go to Help > About. However, if I go to Help > About again, another dialog pops up. I'm trying to get it so that the already opened About dialog is the only one that can be open (i.e. no additional About dialogs allowed). I feel like this should be simple, but I keep getting a Segmentation Fault. Here's my code:
myApp.h
#ifndef MYAPP_H
#define MYAPP_H
#include <QMainWindow>
#include "about.h"
namespace Ui {
class MyApp;
}
class MyApp : public QMainWindow // inherit all public parts of QMainWindow
{
Q_OBJECT
public:
explicit MyApp(QWidget* parent = 0);
~MyApp();
private slots:
void on_actionAbout_triggered();
private:
Ui::MyApp* ui;
About* aboutDialog;
};
#endif // MYAPP_H
MyApp.cpp
#include "MyApp.h"
#include "ui_MyApp.h"
#include "about.h"
MyApp::MyApp(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MyApp)
{
ui->setupUi(this);
}
MyApp::~MyApp()
{
delete ui;
}
void MyApp::on_actionAbout_triggered()
{
if (!aboutDialog) {
aboutDialog = new About(this); // create new window
}
aboutDialog->show();
aboutDialog->activateWindow();
}
about.h
#ifndef ABOUT_H
#define ABOUT_H
#include <QDialog>
namespace Ui {
class About;
}
class About : public QDialog
{
Q_OBJECT
public:
explicit About(QWidget* parent = 0);
~About();
private:
Ui::About* ui;
};
#endif // ABOUT_H
about.cpp
#include "about.h"
#include "ui_about.h"
About::About(QWidget* parent) :
QDialog(parent),
ui(new Ui::About)
{
ui->setupUi(this);
}
About::~About()
{
delete ui;
}
In MyApp.cpp, when I get rid of the if, it works. But clicking Help > About (actionAbout_triggered) multiple times will open a bunch of About windows. I just want 1. So I figured I'd put in an if statement that says, if the About dialog is already open, don't create another one and just make it the active window instead. I'm met with a Segmentation Fault. I know this means it's trying to access memory somewhere that it shouldn't be, but I don't know why.
Any help would be greatly appreciated.
The normal way of doing this is to have a modal dialog box for your About window. Something like this
void MyApp::on_actionAbout_triggered()
{
About dlg(this);
dlg.exec();
}
Regarding your question specifically, the problem is you did not initialize aboutDialog to anything in the MyApp constructor, so it is "undefined value" - probably not null.
Set aboutDialog to null in your MyApp constructor to solve your segfaults.
I am trying to connect a signal from a second QMainWindow to the mainwindow. It doesn't say anything about a problem connection when the program is launched, but It doesn't work. I am not very familiar with C++ and Qt so maybe is something simple.
My code consists on a Mainwindow used as a SCADA with Start, stop, On, off buttons. In the second qmainwindow I created a terminal where you can type, start,stop... There, I would like to emit a signal to my MainWindow which is in charge of controlling the multiple threads and windows. The problem is that I cannot connect to my slot. I present here a simple overview of this two pieces of code.
Terminal. h
#ifndef TERMINAL__H
#define TERMINAL__H
#include <QMainWindow>
#include <QTextEdit>
#include <QLineEdit>
#include <QObject>
namespace Ui {
class Terminal_;
}
class Terminal_ : public QMainWindow
{
Q_OBJECT
public:
explicit Terminal_(QWidget *parent = 0);
~Terminal_();
signals:
void turnonPLC_terminal();
public slots:
void newline();
private:
Ui::Terminal_ *ui;
QTextEdit* mTerminal;
QLineEdit* mInput;
};
#endif // TERMINAL__H
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "terminal_.h"
#include "terminal_help.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Terminal_ *terminal;
public slots:
void turnon_terminal();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "terminal_.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
terminal = new Terminal_(this);
connect(terminal, SIGNAL(turnonPLC_terminal()), this, SLOT(turnon_terminal()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::turnon_terminal(){
turnonPLC=1;
}
terminal_.cpp
#include "terminal_.h"
#include "ui_terminal_.h"
#include <QDockWidget>
#include <QWidget>
#include <QLineEdit>
QString on=("on");
Terminal_::Terminal_(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Terminal_)
{
ui->setupUi(this);
mTerminal = new QTextEdit();
setCentralWidget(mTerminal);
mInput = new QLineEdit();
QDockWidget* qdw = new QDockWidget;
qdw->setWidget(mInput);
addDockWidget(Qt::BottomDockWidgetArea, qdw);
connect (mInput, SIGNAL(returnPressed()),
this, SLOT(newline()));
}
Terminal_::~Terminal_()
{
delete ui;
}
void Terminal_::newline(){
QString command = mInput->text();
if (command==on){
emit turnonPLC_terminal();
}
}
Thanks
The signal-slots part in the code works perfectly. (compiled and tested with some small modifications)
After entering "on" (not On as written in question)
Terminal_::newline() slot called, turnonPLC_terminal() is fired and finally
void MainWindow::turnon_terminal() is called.
However, there are some small details the header file is called terminal_.h, not Terminal.h turnonPLC is not defined. terminal is created by not displayed (no show-call).
I guess, there are simply some many small logic errors. Try to use debugger or trace the chain of expected calls with qDebug.