Working with two user interfaces - Qt 5.5 - c++

I have a simple MainWindow which has a button and an LineEdit. When I type something and click a button, a new Dialog appears with a label that is supposed to display the string I typed.
So basically, I have trouble sending information to another UI.
I tried working with the new class with a string variable, but it didn't work.
I will try to give an example of what I want to do.
//ui2 Dialog
ui2->label->setText(ui->LineEdit->text());

Ui is a an private variable, so it's not accessible from another class.
//mainwindow.cpp
MainWindow::MainWindow(QWidget*){
this->_dialog = new Dialog(this);
//...
}
MainWindow::on_pushButton_clicked(){
_dialog->_labe->setText(ui->lineEdit->text());
}
//dialog.h
class Dialog{
public:
QLabel* _label;
Dialog(QWidget* ){
_label = ui->label;
}
}

Related

How to pass multiple variables from QT Dialog to Main Window

I have a press button (pushButton_RenameTargets) and 3 labels (label_Tar1ex, label_Tar2ex, label_Tar3ex) on my main form with default text values. When I push the button (pushButton_RenameTargets) a dialog is created (renametargets). It has three text edit lines (lineEdit_Target1, lineEdit_Target2,lineEdit_Target3). When I enter names on the three text edit lines and push OK I want the 3 labels on my main form to update.
Better Described:
When the button is pressed:
void MainWindow::on_pushButton_RenameTargets_clicked()
{
RenameTargets renametargets;
renametargets.setModal(true);
renametargets.exec();
}
It creates the dialog window renametargets.
Window has three text edit lines (lineEdit_Target1, lineEdit_Target2,lineEdit_Target3).
When the OK button is pushed I store the text in QString variables.
void RenameTargets::on_buttonBox_TargetRename_accepted()
{
QString Target1NameInput = ui->lineEdit_Target1->text();
QString Target2NameInput = ui->lineEdit_Target2->text();
QString Target3NameInput = ui->lineEdit_Target3->text();
}
Questions:
(1) How can I set the text of QString Target1NameInput (located on second form: renametargets) to label_Tar1ex (located on main form) as I push the OK button on the dialog.
(2) How can I get to display label_Tar1ex (located on main form) to display on a label in the second form -- called label_CurrentName_Tar1ex.
Basically this is a renaming scheme.....
What I would do is declare Target1NameInput and others in your dialog's class instead of your Ok function. That way those variables always "exist" while your dialog exists. If you create them in your Ok function, then they vanish when that function ends, and then you can't get them from your mainWindow anymore.
Move the variable declarations to your dialog's class. (They go in public so other classes can get at em)
class RenameTargets : public QDialog
{
Q_OBJECT
public:
QString Target1NameInput; //Side note, variable naming convention says
QString Target2NameInput; //that variables should start with a lowercase
QString Target3NameInput; //letter, but totally up to you ;)
//Your other class stuff goes here
}
From that point you can set those variables in your dialog when Ok is pressed.
void RenameTargets::on_buttonBox_TargetRename_accepted()
{
Target1NameInput = ui->lineEdit_Target1->text();
Target2NameInput = ui->lineEdit_Target2->text();
Target3NameInput = ui->lineEdit_Target3->text();
}
And lastly, access those variables in your mainWindow.
void MainWindow::on_pushButton_RenameTargets_clicked()
{
RenameTargets renametargets;
renametargets.setModal(true);
if(renametargets.exec() == QDialog::Accepted) //Check if they clicked Ok
{
ui->label_Tar1ex->setText(renametargets.Target1NameInput);
ui->label_Tar2ex->setText(renametargets.Target2NameInput);
ui->label_Tar3ex->setText(renametargets.Target3NameInput);
}
}
As for your second question, sending from mainWindow to dialog, you have 2 options as I see it.
Set your string variables we created in your dialog class before exec().
Pass the text in your dialog constructor.
If option 1, then you simply call renametargets.Target1NameInput = ui->label_Tar1ex->text(); for each variable before you call renametargets.exec(); Then in your dialog's ui setup, you set your lineEdits text to those same variables.
Let me know if you want me to explain option 2 for you. ;)
There's also many other options to send variables between classes, this is just 1 of those ways. I believe the conventional thing to do would be to have get and set functions within your dialog class, but for my own personal projects, I find that overkill. Up to you.
if (editDocumentDialog->exec() == QDialog::Accepted)
{
editDocumentDialog->getDataRecord(theDocRecord);
documents->updateRecord(theDocRecord);
}
Why not using signal / slot?
void MainWindow::on_pushButton_RenameTargets_clicked()
{
RenameTargets renametargets;
connect(&renametargets, SIGNAL(name_inputted), this, SLOT(update_name_fields);
...
}
Then emit the signal in on_buttonBox_TargetRename_accepted, and update label_Tar1ex... in slot function. You may want to create RenameTargets in heap so it isn't destroyed immediately after its OK is clicked.

Qt Change ComboBox2 based on ComboBox1

Hi I am fairly new to Qt scene and I'm having trouble updating my comboBox2 based on comboBox1 selection.
Everytime I make a change in comboBox1, my app crashed, saying access violation. It's probably very straightforward but here's my code: In this case, the initial comboBox1 has "Car" and "Food". Whenever I switch to "Food", I want my comboBox2 to populate the item "Egg".
Any idea what went wrong ?
main.h
class main:
{
Q_OBJECT
public:
main() {}
public slots :
private slots:
void onComboBoxIndexChanged();
private:
QComboBox* comboBox2;
void run();
};
main.cpp
void main::run()
{
QWidget *w = new QWidget();
QComboBox *comboBox1 = new QComboBox();
QComboBox *comboBox2 = new QComboBox();
comboBox1->addItem("Car");
comboBox1->addItem("Food");
connect(comboBox1, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxIndexChanged()));
...
}
void main::onComboBoxIndexChanged()
{
QComboBox* combo = dynamic_cast<QComboBox*>(sender());
if (combo == nullptr)
{
return;
}
comboBox2->addItem("Egg");
}
You didn't fix your typo correctly. There's three things I see wrong, and I would've thought the third one would prevent this from compiling.
First, main.h says that your class name is "main", but in main.cpp, your class is WIPGui. Clearly one of those files isn't the right one. I'm going to proceed assuming that your actual main.h file defines the WIPGui class, but otherwise looks the same.
Second, as Mike tried to point out, in your run function, you have this:
QComboBox *comboBox2 = new QComboBox();
That's creating a local variable in your "run" method; it is not assigning to your class member variable comboBox2. What you want is:
comboBox2 = new QComboBox();
Third, your connect statement shouldn't compile based on the code we're seeing:
connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxIndexChanged()));
The "comboBox" variable doesn't exist anywhere in this code. If you've actually used "comboBox1" in the connect statement, but this is just another typo in the code you've presented here, then the connect statement is fine. If this is a cut-and-paste as-is, then I don't see how this compiles.
Assuming that you've used "comboBox1" in the connect statement, then the real problem is that you're never assigning to the member variable "comboBox2" and when your slot tries to use it, you get a crash.

Why is the recommended QDialog instantiation the way it is?

I have a Qt Widgets application, created and edited in Qt-Creator.
The main window (MainWindow class) has a menubar, with a button to open a small dialog (with text or widgets for settings).
To create a new "window" I open the "create new file" dialog in Qt-Creator and select Qt Designer Form Class, which creates the needed header, source, and ui files (dialogabout.h, dialogabout.cpp, dialogabout.ui).
If I follow along with the docs, I then open the QDialog like so:
QDialog * widget = new QDialog;
Ui::DialogAbout about_ui;
about_ui.setupUi(widget);
widget->exec();
This works, but if I modify the new dialog's instantiator to connect a pushbutton to the close signal, the connect statement (along with any other code there) is never reached.
DialogAbout::DialogAbout(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogAbout)
{
ui->setupUi(this);
qDebug() << "I'm alive!"; // No output happens
connect(ui->pushButton_close, SIGNAL(clicked(bool)), this, SIGNAL(please_close())); // No signal created on pushbutton click.
}
I suspect that this is because I haven't explicitly done widget = new DialogAbout(this). If I instead instantiate the new dialog this different way:
DialogAbout * newwindow;
newwindow = new DialogAbout(this);
newwindow->exec();
Then the connect statement and qDebug work.
My question is: what are the pitfalls of deviating from the documentation's recommended way to create dialogs? Is there a way to get this functionality with the prior instantiation method?
Note that DialogAbout is not the same as Ui::DialogAbout. Ui::DialogAbout is a class of build placed in the UI namespace, created automatically by uic. In your project, the name of this file should be "ui_dialogabout h".
class Ui_DialogAbout
{
public:
QPushButton *pushButton_close;
void setupUi(QDialog *DialogAbout)
{
...
} // setupUi
void retranslateUi(QDialog *DialogAbout)
{
...
} // retranslateUi
};
namespace Ui {
class DialogAbout: public Ui_DialogAbout {};
} // namespace Ui
Here you use a class QDialog and uses the Ui::DialogAbout to build a layout in it. Note that Ui::DialogAbout has the function to create the components in QDialog.
QDialog * widget = new QDialog;
Ui::DialogAbout about_ui;
about_ui.setupUi(widget);
widget->exec();
If you specialize QDialog for DialogAbout your code should look like this:
DialogAbout * widget = new DialogAbout();
Ui::DialogAbout about_ui;
about_ui.setupUi(widget);
widget->exec();
But as setupUi() is already within DialogAbout, you cannot call again, resulting in:
DialogAbout * widget = new DialogAbout();
widget->exec();

Extending an existing UI for QMainWindow by additional menus with Qt Designer

I have written a basic image viewing application using Qt and C++, i.e. I have a class
ImageViewApp : public QMainWindow, private Ui::ImageViewer {
Q_OBJECT
public:
ImageViewApp ( const char * InputFilename = NULL ) {
setupUi ( this );
}
};
with a .ui file created with Qt Designer, that generates a header file defining
class Ui_ImageViewer {
public:
void setupUi(QMainWindow *ImageViewer) { … }
};
namespace Ui {
class ImageViewer: public Ui_ImageViewer {};
} // namespace Ui
Now I would like to write another application ImageRegistrationApp, where I extend the QMenuBar of ImageViewApp by additional QMenus containing QActions for a certain purpose, say image registration. Additionally, I would like to change some other things, such as the windowTitle and add QActions to existing QMenus of ImageViewApp.
I am looking for a way where I don't need to touch or copy the the .ui file of ImageViewApp. I would like to do something like inheritance, where changes to the UI of ImageViewApp affect the UI of ImageRegistrationApp. Also I would like to be able to create and edit the additional QMenus and QActions for ImageRegistrationApp via Qt Designer.
Is this possible?
UPDATE:
I tried changing the title of ImageRegistrationApp and adding a QAction to an existing QMenu in ImageViewApp through inheritance within C++ as follows:
ImageRegistrationApp : public ImageViewApp {
Q_OBJECT
public:
QAction *actionTest;
ImageRegistrationApp ( const char * InputFilename = NULL )
: ImageViewApp ( InputFilename ) {
this->setWindowTitle(QApplication::translate("ImageViewer", "ImReg", 0, QApplication::UnicodeUTF8));
actionTest = new QAction(this);
actionTest->setObjectName(QString::fromUtf8("actionTest"));
actionTest->setText(QApplication::translate("ImageViewer", "Test", 0, QApplication::UnicodeUTF8));
this->menuTools->addAction(actionTest);
}
protected slots:
void on_actionTest_triggered() {
QMessageBox::information(NULL, "Test", "Hello world!" );
}
};
I also changed the inheritance in ImageViewApp to protected Ui::ImageViewer in order to be able to access the Ui elements.
The title of my ImageRegistrationApp changes as intended and also the QAction Test shows up in the menu Tools, but when I click it, nothing happens though I expect it to display the QMessageBox as defined in the slot on_actionTest_triggered.
Is there anything else I have to do, to connect the QAction with the slot?
I tried QObject::connect(actionTest, SIGNAL(triggered()), this, SLOT(actionTest)); but this did not change anything.
The problem with the slot not being executed when the QAction actionTest was triggered, was a misspelling. I had also tried QObject::connect(actionTest, SIGNAL(on_triggered()), this, SLOT(on_actionTest_triggered)); before, but there were the () missing at the end.
Adding the following line at the end of the constructor of ImageRegistrationApp solved the problem:
QObject::connect(actionTest, SIGNAL(on_triggered()), this, SLOT(on_actionTest_triggered()));
Instantiating ImageRegistrationApp now instantiates the entire GUI of ImageViewApp and adds the additionally defined QActions to the respective QMenus. This method should be capable of everything I asked for in the question, except for designing additional QMenus with Qt Designer. Instead, everything has to be coded in C++ source.

Qt Run Single Application

I have a few dialogs and buttons that call these dialogs. However, every click on the button calls a new dialog window. I want the existing window to close first before the user can click on the button to open another.
Below is an example of a button calling a slot. Whenever I click on the button, it will call a copy of the dialog window. Is there any way to only call one copy of the dialog window only?
Thanks.
Bookmark.cpp:
Bookmark::Bookmark()
{
createButtons();
connect(bookmarkButton, SIGNAL(clicked()), this, SLOT(openBookmarkDlg()));
}
void Bookmark::createButtons()
{
...
bookmarkButton = new QToolButton;
bookmarkButton->setText("Bookmark");
addWidget(bookmarkButton);
...
}
void Bookmark::openBookmarkDlg()
{
BookmarkDlg *bkDlg = new BookmarkDlg;
bkDlg->show();
}
Bookmark.h:
class Bookmark : public QToolBar
{
Q_OBJECT
public:
Bookmark(void);
~Bookmark(void);
public slots:
void openBookmarkDlg();
private:
createButtons();
QToolButton *bookmarkButton;
};
If you want the dialog window to be modal, i.e. the application doesn't accept user input outside the dialog, use the window modality of the dialog.
Beware however that modal windows can be really annoying to users.
If BookmarkDlg inherits QDialog you can do the following:
void Bookmark::openBookmarkDlg()
{
BookmarkDlg *bkDlg = new BookmarkDlg;
prepareYourDialog(bkDlg);
/*If you expect to do something when the dialog is accepted*/
if (bkDlg->exec() == QDialog::Accepted)
{
/*Do something after dialog was accepted, and nothing when canceled*/
}
delete bkDlg;
}
Convert BookmarkDlg *bkDlg into a variable member of the class, instead of a local variable of the method:
private:
createButtons();
QToolButton *bookmarkButton;
BookmarkDlg *bkDlg;
Then on the implementation of the class, you could do:
void Bookmark::openBookmarkDlg()
{
if (!bkDlg)
bkDlg = new BookmarkDlg;
bkDlg->show();
}