I'm trying to perform action, when user clicks on button.
My code is:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtUiTools/QUiLoader>
#include <QFile>
#include <QMessageBox>
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
createActions();
}
void MainWindow::test()
{
//QMessageBox::information(this, "Welcome", "Select first image.");
//QFileDialog::getOpenFileName(this, QT_TR_NOOP("Open Image"), "D:\\", QT_TR_NOOP("Image Files (*.png *.jpg *.bmp)"));
resize(100,500);
}
void MainWindow::createActions()
{
QWidget *centralWidget = this->centralWidget();
QPushButton *buttonBack = centralWidget->findChild<QPushButton *>("pushButton");
QObject::connect(buttonBack,SIGNAL(clicked()), this, SLOT(test()));
QAction *open = this->findChild<QAction *>("actionOpen");
//QMessageBox::information(this, "Welcome", open->text());
connect(open, SIGNAL(triggered()), this, SLOT(test()));
}
Function void MainWindow::test() is defined as SLOT in header file and I'm sure, that QPushButton *buttonBack isn't null. What I'm doing wrong?
In my code I tried also to perform action through QAction, but in this case, function is performed, when I close window.
It looks like you're setting all your actions in the destructor.
Think about what this is doing:
UI starts up all happy with the setupUi() call from the constructor
Throughout the lifetime of the UI, there are no buttons assigned to any slots. This means the signal from your button will never get to the slot test().
Upon exit of the UI, the button is connected to the slot.
If you want this to happen, that's cool, but if you want the button to connect to the slot while the UI is running, move your createActions() function into the constructor.
Good luck!
Related
I'm new to any form of programming but have to do a project with Qt for my "programming for engineers" course where we simultaneously learn the basics of c++.
I have to display a text from one lineEdit to a lineEdit in another window.
I have a userWindow that opens from the mainWindow and in this userWindow I have a lineEdit widget that displays the current selected user as a QString (from a QDir object with .dirName() ). But now I have to display the same String in a lineEdit in the mainWindow as well.
From what I've read I have to do this with "connect(...)" which I have done before with widgets inside a single .cpp file but now I need to connect a ui object and signal from one window to another and I'm struggling.
My idea /what I could find in the internet was this:
userWindow.cpp
#include "userwindow.h"
#include "ui_userwindow.h"
#include "mainwindow.h"
#include <QDir>
#include <QMessageBox>
#include <QFileDialog>
#include <QFileInfo>
QDir workingUser; //this is the current selected user. I tried defining it in userWindow.h but that wouldn't work how I needed it to but that's a different issue
userWindow::userWindow(QWidget *parent) : //konstruktor
QDialog(parent),
ui(new Ui::userWindow)
{
ui->setupUi(this);
QObject::connect(ui->outLineEdit, SIGNAL(textChanged()), mainWindow, SLOT(changeText(workingUser) //I get the error " 'mainWIndow' does not refer to a value "
}
[...]
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDir>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void changeText(QDir user); //this is the declaration of my custom SLOT (so the relevant bit)
private slots:
void on_userButton_clicked();
void on_settingsButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "userwindow.h"
#include "settingswindow.h"
#include "click_test_target.h"
#include "random_number_generator.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
[...]
}
[...]
//here I define the slot
void MainWindow::changeText(QDir user)
{
QString current = user.dirName();
ui->userLine->insert("The current working directory is: "); //"userLine" is the lineEdit I want to write the text to
ui->userLine->insert(current);
}
I know I'm doing something wrong with the object for the SLOT but can't figure out how to do it correctly.
If anyone could help me I would be very grateful.
Alternatively: perhaps there is another way to mirror the text from one lineEdit to another over multiple windows. If anybody could share a way to do this I would be equally grateful. Is there maybe a way to somehow define the variable "QDir workingUser;" in such a way as to be able to access and overwrite it in all of my .cpp files?
Thank you in advance for any help. Regards,
Alexander M.
"I get the error 'mainWindow' does not refer to a value"
I don't see you having any "mainWindow" named variable anywhere,
but you also mentioned that the MainWindow is the parent, which means you could get reference anytime, like:
MainWindow *mainWindow = qobject_cast<MainWindow *>(this->parent());
Also, your signal-handler (changeText(...) slot) should take QString as parameter (instead of QDir), this way you handle how exactly the conversion is handled, in case users type some random text in input-field (text-edit).
void changeText(const QString &input);
Finally, you either need to specify type:
QObject::connect(ui->outLineEdit, SIGNAL(textChanged(QString)), mainWindow, SLOT(changeText(QString));
Or, use the new Qt-5 syntax:
connect(ui->outLineEdit, &QLineEdit::textChanged,
mainWindow, &MainWindow::changeText);
You can create new signal (same params as lineEdit's textChanged) to userWindow which is connected to the textChanged signal of the lineEdit. Then connect that signal userWindow to mainWindow's slot.
//In userWindow.h
signals:
void textChanged(const QString&);
//In userWindow.cpp
connect(ui.lineEdit, &QLineEdit::textChanged, this, &userWindow::textChanged);
//In mainWindow.cpp
connect(userWindow, &userWindow::textChanged, this, &mainWindow::onTextChanged
Then in onTextChanged write the same text to mainWindow's lineEdit
Pretty much this window opens up and asks for a bandname. I got it so the characters on the line edit widget get stored in a variable. Problem is I have another file called main window.cpp and I want that variable to to be stored on the list widget on that window. Now I know how to display things on the list widget but I can't figure out a way to get the text after the user finished typing. The bandname var in the main window.cpp file just takes an empty string and I know why but is there any way to trigger the get call after the user has finished typing. Do I have to restrict something in the class like the get function. I've experimented a lot and saw callbacks but I could just use signals and slots. Everything Ive tried just returns an empty string but I need the text after the user has finished typing what he wants. Here is the dialog window named add button
#include "addbutton.h"
#include "ui_addbutton.h"
AddButton::AddButton(QWidget *parent) :
QDialog(parent),
ui(new Ui::AddButton)
{
ui->setupUi(this);
connect(ui->cancel,SIGNAL(released()),this,SLOT(close()));
//Get Text when user presses enter
connect(ui->lineEdit, SIGNAL(editingFinished()),this,SLOT(setBandName()));
}
void AddButton::setBandName(){
bandname = ui->lineEdit->text();
}
void AddButton::updateState(){
pbandname = bandname;
}
QString AddButton::getBandName(){
return bandname;
}
AddButton::~AddButton()
{
delete ui;
}
Here is the main window.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "addbutton.h"
#include "bandinfo.h"
#include "QDebug"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mediaplayer = new Player;
connect(ui->pushbutton_addBand,SIGNAL(pressed()),this,SLOT(addBand()));
}
void MainWindow::addBand(){
BandInfo band;
AddButton *addband_window = new AddButton;
QString bandname;
addband_window->show();
bandname = addband_window->pbandname;
qDebug() << bandname;
}
MainWindow::~MainWindow()
{
delete ui;
}
I'm not sure I understand your post. Are you saying you want the main window to be notified/updated when the user finishes editing in the "AddButton" class?
If I've got that right it seems pretty straightforward:
Add a signal to the AddButton class. Call it something like "bandNameChanged".
Make the signal pass a string as its argument
Emit the signal from within AddButton::setBandName and pass the string name.
Have the main window connect a slot to the "bandNameChanged" signal when it creates the AddButton.
In the slot, update your list widget
I'm really stuck on one problem that I want to solve. the problem is that I have a Class for QMainWindow which holds the Ui variable for that form. Now I want to be able to edit that Form using the Ui variable in that class on a QDialog cpp file. I probably sound really stupid and I really have no idea how I should explain this, but I have code which maybe can help.
MainWindow.h:
#include "ui_mainwindow.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
Ui::MainWindow *ui;
}
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog.h"
Dialog *dialog;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
dialog->show();
}
QDialog.cpp:
#include "ui_mainwindow.h"
#include "mainwindow.h"
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
Ui::MainWindow *mainui;
void Dialog::on_pushbutton_clicked(){
mainui->label->setText("test");
}
So as you can see from the above code, it shows that I have a pointer to the Ui variable however its uninitialised, therefore it would lead to a SIGSEGV error, so how to do Initialize this pointer? any help here is highly appreciated, and even though this is probably really simple I just don't know what to do. (I have looked at other questions but I couldn't quite grasp what to do, so please explain what I am to do before linking me to a similar question. Also, I have left out the Dialog.h file as I didn't think it was needed, please tell me if I need to show it, thanks!).
Generally in C++ you should practice what is called encapsulation - keep data inside a class hidden from others that don't need to know about it. It's not good to have multiple pointers to the UI object as now all those other objects have to know how the main window UI is implemented.
In this case, what I would recommend is to use Qt's signals and slots mechanism to allow the dialog to tell the main window what you need it to do. That has the advantage that if you add more dialogs, or change how things are implemented in the main window, you don't need to alter the signal slot mechanism, and the details are hidden cleanly.
So - for your dialog, add a signal like this in the header file
class Dialog : QDialog
{
Q_OBJECT
signals:
void setTextSignal(QString text);
}
and in your main window header, add a slot.
class MainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void setTextSlot(const QString &text);
}
now in your method where the button is pressed,
void Dialog::on_pushbutton_clicked()
{
emit setTextSignal("test");
}
and in your main window
void MainWindow::setTextSlot(const QString &text)
{
mainUi->label->setText(text);
}
The final part is to connect the signal and slot together, which you would do in your main window function where you create the dialog:
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
connect(dialog, SIGNAL(setTextSignal(QString)), this, SLOT(setTextSlot(QString)));
dialog->show();
}
You can see there are many advantages to this; the Dialog no longer needs a pointer to the main window UI, and it makes your code much more flexible (you can have other objects connected to the signals and slots as well).
Short answere - your can't! If you want to create a new instance of the ui, you would have to do:
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(this);
However, the this-pointer for a UI created for a QMainWindow based class must inherit QMainWindow - thus, you can't.
In general, it is possible if you create your Ui based on a QWidget instead of a QMainWindow, since both inherit QWidget.
Alternativly, you could try the following:
QMainWindow *subWindow = new QMainWindow(this);
subWindow->setWindowFlags(Qt::Widget);
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(subWindow );
//... add the mainwindow as a widget to some layout
But I would guess the result will look weird and may not even work in the first place.
I have the following code to display a pushbutton, i am new to qt and can't figure out why its not working.
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QtWidgets>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QWidget* wdg = new QWidget(this);
QPushButton *button = new QPushButton(wdg);
button->setText(tr("something"));
setCentralWidget(wdg);//line 1
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
if i remove line1 then the button is being displayed but it is not clickable.
When ui->setupUi(this); is called, the user interface that is created in Qt designer stored in .ui file is initialized. It constructs the widgets and calls setCentralWidget internally. So when it is called the central widget is replaced by the one you set.
Either make the user interface by your own and ignore ui->setupUi(this); or first call ui->setupUi(this); in the constructor and do the rest of initializations by your own if you wish.
I have a qslider to control the zooming of a map like this:
connect(ui->zoomSlider, SIGNAL(valueChanged(int)), ui->map, SLOT(SetZoom(int)));
However, because this online-map response relatively slow.
I found that the qslider's response also becomes very slow which means when you slide the slider, it's position won't change until suddenly it jump to the position where you release your mouse.
How could I solve this?
One possible solution to delay processing of your signal is to connect it with slot by using Qt::QueuedConnection.
connect(ui->zoomSlider, SIGNAL(valueChanged(int)), ui->map, SLOT(SetZoom(int)), Qt::QueuedConnection);
With Qt::QueuedConnection emitted valueChanged signal event will be not processed at the time of generation, as it happens with directly connected signals. Event will be added to the event loop queue. This is how Qt::QueuedConnection is implemented inside Qt.
Specially for Nejat to test this approach it's possible to use following code:
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 signalReceived();
void signalReceivedQueued();
void buttonPressed();
signals:
void directConnectedSignal();
void queuedConnectedSignal();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(this, SIGNAL(directConnectedSignal()), SLOT(signalReceived()), Qt::DirectConnection);
connect(this, SIGNAL(queuedConnectedSignal()), SLOT(signalReceivedQueued()), Qt::QueuedConnection);
connect(ui->pushButton, SIGNAL(pressed()), SLOT(buttonPressed()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::signalReceived()
{
qDebug() << "signalReceived";
}
void MainWindow::signalReceivedQueued()
{
qDebug() << "signalReceivedQueued";
}
void MainWindow::buttonPressed()
{
emit queuedConnectedSignal();
emit directConnectedSignal();
}
If you run code snippet above you will get following output on button press:
signalReceived
signalReceivedQueued
Queued signal is emitted first, but received last. And this can be used in your case to prioritize processing of emitted signals.
However most of all using of queued connection will not help you, because user emits slider event too frequently and UI will freeze in any case. So, I can suggest following:
Determine why exactly UI is freezes, what part of code freezing it.
Try to avoid freezing by asynchronous calls or by moving logic into separate thread, or by using QtConcurrent
If you really can't control the way how map is scaled in your webpage, try to ignore all events generated by the QSlider and react only on last generated in 500 ms interval, for example.