I am a newbie in Qt-programming. I have read a book about GUI-programming with Qt. I have an trouble in creating a dialog. Here is sample code:
// gotocell.h
#ifndef GOTOCELL_H
#define GOTOCELL_H
#include <QDialog>
#include <QtWidgets>
#include "ui_gotocell.h"
class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
{
Q_OBJECT
public:
GoToCellDialog (QWidget *parent = 0);
private slots:
void on_lineEdit_textChanged();
};
#endif // GOTOCELL_H
// gotocell.cpp
#include <QtWidgets>
#include "gotocell.h"
#include <QtWidgets>
GoToCellDialog::GoToCellDialog (QWidget *parent):
QDialog (parent)
{
setupUi(this);
QRegExp regExp ("[A-Za-z][1-9][0-9]{0,2}");
lineEdit->setValidator(new QRegExpValidator(regExp, this));
connect (okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect (cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
}
void GoToCellDialog::on_lineEdit_textChanged()
{
okButton->setEnabled(lineEdit->hasAcceptableInput());
}
// main.cpp
#include "gotocell.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GoToCellDialog *dialog = new GoToCellDialog;
dialog->show();
return a.exec();
}
but when I compiled, there is an error: no known conversion for argument 1 from 'GoToCellDialog* const' to 'QMainWindow*'at setupUi() function. I think because the designer in Qt Creator created a QMainWindow, not a QDialog. So I changed GoToCellDialog class to QMainWindow. But there is no slots whose name is "accepted", "rejected" in QMainWindow. Can anyone help me?
If you want to display a Dialog as main window you have two choices:
1. make the whole main window QDialog based
2. design the Dialog separately and set it as the main windows central Widget (QMainWindow->setCentralWidget()).
In both cases you still have the problem what semantics you give to the OK and Cancel buttons. Generally it may be a better idea to consider what the main window of the application should contain, and design the dialogs later.
Related
I'm building up an application, which receives data over the serial interface. So i implemented a class for the serial handling, which can successfully receive and send data. Now I try to move the data to the UI, to give it out to a console, but I need a thread for that and it seems more difficult than I expected.
So somehow I need to define a thread and start it at the beginning of the UserInterface creation and this thread should then poll a function for new data. I researched about creating a thread and connect it to a callback function, but it is always related to create a class, that inherits from QThread, which I cannot do for the Main UI.
How should I define a thread inside the Main UI, which I can use then to poll a function?
Edit: As recommended, a thread is not necessary here, but I don't know how to call a function inside a class without an object. In the mainWindow class, where all the UI stuff like labels and buttons sits, I created an object for serial communication. Inside this object, an interrupt is called, when new data is received. So I can for example queue this data inside this serial object, but still i need somehow to forward them.
Edit2: A first method that actually works was to implement a timer, which periodically calls an update function. But since the serial rx is interrupt driven, there must be a way for callback, such that I don't need to poll it.
As discussed in the comments, in this use-case it's preferable to not use threading, but exploit the Qt event loop and signal-slot mechanism. Here is the skeleton of the MainWindow and the SerialReciver classes, and how they are wired together in main.cpp. For simplicity, the SerialReceiver class just emits the signal every second with the current time, which will be appended to the editfield's content in the main window.
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPlainTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void onSerialMessage(const QString &msg);
private:
QPlainTextEdit mTextField;
};
mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
mTextField.setReadOnly(true);
setCentralWidget(&mTextField);
}
MainWindow::~MainWindow()
{
}
void
MainWindow::onSerialMessage(const QString &msg)
{
mTextField.appendPlainText(msg);
}
#endif // MAINWINDOW_H
serialreceiver.h:
#ifndef SERIALRECEIVER_H
#define SERIALRECEIVER_H
#include <QObject>
#include <QTimer>
class SerialReceiver : public QObject
{
Q_OBJECT
public:
explicit SerialReceiver(QObject *parent = nullptr);
signals:
void newMsg(const QString &msg);
public slots:
void onSerialReceived();
private:
QTimer mTimer;
};
#endif // SERIALRECEIVER_H
serialreceiver.cpp:
#include "serialreceiver.h"
#include <QDateTime>
SerialReceiver::SerialReceiver(QObject *parent) : QObject(parent)
{
mTimer.setInterval(1000);
mTimer.setSingleShot(false);
connect(&mTimer, &QTimer::timeout,this,&SerialReceiver::onSerialReceived);
mTimer.start();
}
void
SerialReceiver::onSerialReceived()
{
QDateTime now = QDateTime::currentDateTime();
emit newMsg(now.toString());
}
and main.cpp:
#include "mainwindow.h"
#include "serialreceiver.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SerialReceiver receiver;
MainWindow w;
QObject::connect(&receiver, &SerialReceiver::newMsg,
&w,&MainWindow::onSerialMessage);
w.show();
return a.exec();
}
This question already has answers here:
QObject connection function
(3 answers)
Closed 4 years ago.
I am currently making a main menu for a game, but when the button is clicked it does not seem to call the relevant slot (The button does not do anything). I have tried to move the button to a thread to ensure that nothing is keeping it from running immediately. I have written a simpler program where the button works, so it would seem the problem is not with the button or signal itself. Therefore it must be something keeping it from running?
The source file is given as:
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QObject>
#include <QBrush>
#include"game.h"
#include <QMediaPlayer>
#include <QImage>
#include<QGraphicsPixmapItem>
#include <QPixmap>
#include<QGraphicsItem>
#include <QPushButton>
#include <QLineEdit>
#include <QPalette>
#include <QMessageBox>
#include <QLabel>
#include <QComboBox>
Game::Game(QWidget*parent)
{
//adding the background
QGraphicsScene *scene=new QGraphicsScene();//to create a new graphics scene
scene->setSceneRect( 0,0,1366,768);
setBackgroundBrush(QBrush(QImage(":/images/Back_1_withlogo.jpg")));
setScene(scene);
show();
setFixedSize(1366,768);
//adding logo
//setPixmap(QPixmap(":/images/Logo.png"));
//adding the soundtrack
music=new QMediaPlayer();
music->moveToThread(&MusicThread);
music->setMedia(QUrl("qrc:/sounds/Surreal-Game-Menu.mp3"));
music->play();
MusicThread.start();
//add GUI
this->setFixedSize(1366,768);
this->move(-7,-5);
//start button and username edit box
btnStart = new QPushButton(this);
btnStart->moveToThread(&btnThread);
UserName = new QLineEdit(this);
UserName->setFixedSize(100,25);
UserName->move(300,300);
UserName->show();
UserName->setMaxLength(12);
btnStart->setText("Start");
btnStart->setFixedSize(100,30);
btnStart->show();
btnStart->move(300,600);
connect(btnStart, SIGNAL (released()),this, SLOT (btnStart_clicked()));
btnThread.start();
//label for username edit box
QLabel *LblUsername= new QLabel(this);
LblUsername->setStyleSheet("QLabel { color : white; }");
LblUsername->setFixedSize(100,30);
LblUsername->move(230,300);
LblUsername->setText("Username:");
LblUsername->show();
QLabel *lblGameMode = new QLabel(this);
lblGameMode->setStyleSheet("QLabel { color : white; }");
lblGameMode->setFixedSize(100,30);
lblGameMode->move(190,450);
lblGameMode->setText("Select Game mode:");
lblGameMode->show();
//combobox to select players
GameMode=new QComboBox(this);
GameMode->move(300,450);
GameMode->setFixedSize(100,30);
QStringList Modelist=(QStringList()<<"singleplayer"<<"co-op"<<"multiplayer (3 players)");
GameMode->addItems(Modelist);
GameMode->show();
}
void Game::btnStart_clicked()
{
if (UserName->text()==NULL)
{
QMessageBox messageBox;
messageBox.critical(0,"Error","Please insert username!");
messageBox.setFixedSize(500,200);
}
else
{
numPlayers = GameMode->currentIndex();
SUsername= UserName->text();
UserName->setText("works");
}
}
And the header code is given as:
#ifndef GAME_H
#define GAME_H
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QMediaPlayer>
#include <QThread>
#include <QComboBox>
class Game:public QGraphicsView
{
public:
Game(QWidget*parent=0);
QGraphicsScene*scene;
private slots:
void btnStart_clicked();
private:
QPushButton *btnStart;
QLineEdit *UserName;
QMediaPlayer *music;
QThread MusicThread;
QString SUsername;
QThread btnThread;
QComboBox *GameMode;
int numPlayers;
};
#endif // GAME_H
I received the following error:
QObject::connect: No such slot QGraphicsView::btnStart_clicked() in game.cpp:57
add a Q_OBJECT macro as shown below:
class Game:public QGraphicsView
{
Q_OBJECT
public:
Game(QWidget*parent=0);
QGraphicsScene*scene;
private slots:
void btnStart_clicked();
private:
QPushButton *btnStart;
QLineEdit *UserName;
QMediaPlayer *music;
QThread MusicThread;
QString SUsername;
QThread btnThread;
QComboBox *GameMode;
int numPlayers;
};
This macro helps compiler to determine that the class is using signals and slots mechanism. Basically it creates a entry of defined signals and slots in MOC (meta object compiler) file.
Go through below link for info:
http://www.bogotobogo.com/Qt/Qt5_Q_OBJECT_Macro_Meta_Object.php
QObject::connect (btnStart, &QPushButton::clicked, this, &Game::btnStart_clicked); might work... if you want to use the release event try overriding virtual void mouseRelease or the eventFilter.
And of course... the Q_OBJECT marco.
I've recently started learning Qt and I'm a beginner of it now. So as first example for myself I wrote the following simple example.
The example is named Calculator. It now only has two buttons an a line edit. It's here:
:
My Calculator.h is this:
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include<QDialog>
#include "ui_Calculator.h"
class Calculator : public QDialog, public Ui::Calculator
{
Q_OBJECT
public:
Calculator(QWidget* parent = 0);
private slots:
void myslot();
};
#endif // CALCULATOR_H
And the Calculator.cpp is this:
#include <QtWidgets>
#include "calculator.h"
Calculator::Calculator(QWidget *parent)
:QDialog(parent)
{
setupUi(this);
connect(oneButton,SIGNAL(clicked(bool)), this, SLOT(myslot()));
}
void Calculator::myslot(){
lineEdit -> setText("1");
}
And this is the main.cpp:
#include <QApplication>
#include <QDialog>
#include "ui_Calculator.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Ui::Calculator ui;
QDialog* dialog = new QDialog;
ui.setupUi(dialog);
dialog -> show();
return app.exec();
}
The program runs fine without any error. But when I click on 1 button, nothing will be printed/shown in the line edit. Why please?
And what part of my program should I change to solve the issue please?
You are setting up the wrong class in your main.
You should use your custom Calculator class and not QDialog.
setupUi only initializes your elements but your code in Calculator never gets called. Your main should look like this:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Calculator calc; //using your Calculator class.
calc.show();
return app.exec();
}
And don't include ui_calculator.h but calculator.h
I'm a Qt newbie, working in Qt Creator 3.1.2 (Ubuntu Linux), Qt 5.3.1.
My program has a form with a button (pushButton) which changes the value of a text field (plainTextEdit) on being pressed. Both pushButton and plainTextEdit have been added in graphical mode. Connection between the button and its slot (on_pushButton_clicked()) has been set up via the graphical interface too.
The problem is, the program produces a bogus plainTextEdit, i.e. a different one, in the upper left corner, where the output goes to, while the "main" one stays clean. The question hence is, how I can avoid it? In general, how should I connect graphical widgets and their counterparts in the code? Here is my program:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QPlainTextEdit>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QPushButton *pushButton;
QPlainTextEdit *plainTextEdit;
};
#endif // MAINWINDOW_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"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
plainTextEdit = new QPlainTextEdit(this);
// whenever I remove the previous line, I get SIGSEGV
setWindowTitle(tr("My test app..."));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
plainTextEdit->setPlainText("Some text here");
}
It's the widget you're creating in your constructor that is "bogus". The widgets you created in the forms editor belong to the Ui::MainWindow, you must not re-create them in your main window.
Remove this from your MainWindow:
QPushButton *pushButton;
QPlainTextEdit *plainTextEdit;
Remove the widget creation from the constructor:
plainTextEdit = new QPlainTextEdit(this);
Change your on_pushButtonClicked member to:
ui->plainTextEdit->setPlainText("Some text here");
I am trying to implement a input method with Qt Embedded.
There is a lookup table for choosing the candidate words for typing. "text input area" to the "lookup table" and the selected word cannot be sent to the "text input area".
Dose anyone have any idea to solve this problem? Thanks~
Here I give a simple example:
main.cpp
#include "InputWidget.h"
#include "ButtonWidget.h"
#include <QApplication>
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
InputWidget *inputWidget=new InputWidget();
ButtonWidget *buttonWidget=new ButtonWidget();
inputWidget->show();
buttonWidget->show();
int ref=app.exec();
inputWidget->deleteLater();
buttonWidget->deleteLater();
return ref;
}
InputWidget.h
#include <QWidget>
#include <QPlainTextEdit>
#ifndef _InputWidget_H_
#define _InputWidget_H_
class InputWidget:public QWidget
{
Q_OBJECT
public:
InputWidget(QWidget *parent=0);
private:
QPlainTextEdit *inputArea;
};
#endif
InputWidget.cpp
#include "InputWidget.h"
#include <QPushButton>
#include <QVBoxLayout>
InputWidget::InputWidget(QWidget *parent):QWidget(parent)
{
//input area setup
inputArea=new QPlainTextEdit(this);
//main layout
QVBoxLayout *mainLayout=new QVBoxLayout(this);
mainLayout->setContentsMargins(1,4,1,1);
mainLayout->addWidget(inputArea);
setLayout(mainLayout);
}
ButtonWidget.h
#include <QWidget>
#include <QPushButton>
#ifndef _ButtonWidget_H_
#define _ButtonWidget_H_
class ButtonWidget:public QWidget
{
Q_OBJECT
public:
ButtonWidget(QWidget *parent=0);
private:
QPushButton *selectedBtn;
public slots:
void changeBtnText();
};
#endif
ButtonWidget.cpp
#include "ButtonWidget.h"
#include <QPushButton>
#include <QVBoxLayout>
ButtonWidget::ButtonWidget(QWidget *parent):QWidget(parent)
{
//selectedBtn setup
selectedBtn=new QPushButton(tr("Click Me!!"),this);
connect(selectedBtn,SIGNAL(clicked()),this,SLOT(changeBtnText()));
//main layout
QVBoxLayout *mainLayout=new QVBoxLayout(this);
mainLayout->setContentsMargins(1,4,1,1);
mainLayout->addWidget(selectedBtn);
setLayout(mainLayout);
}
void
ButtonWidget::changeBtnText()
{
selectedBtn->setText("I am clicked :)");
}
Those codes would generate a widget which has a PlainTextEdit "inputArea" and a widget which has a PushButton "selectedBtn".
First, I input some words in the "inputArea". The current foucs is on "inputArea" in the InputWidget.
But when I move mouse to ButtonWidget and click the "selectedBtn", the foucs is changed to "selectedBtn" in the ButtonWidget.
How do I click the "selectedBtn" but still keep the foucs on "inputArea"? Thanks~
Just like my comment described in laura's answer, InputWidget and ButtonWidget may have no identical parent and I cannot use QWidget's "setFocus" slot to change the current focus between them.
First of all, you will need to make the two widgets know about each other. Once you have done that (by setting the text widget into the button widget or by adding them both to the same parent widget), you can try to see if QWidget's setFocus slot can help you (look at the other slots too, some might be useful for this).
Perhaps implement something like this, in the ButtonWidget:
(in the header) declare a signal foo()
(in the constructor) connect button widget's foo signal to InputWidget's setFocus slot
(in the changeBtnText) after you've done everything you wanted, emit foo()
Note though that setFocus works if the window is active.
You might be able to get what you want by playing with the focusPolicy for your widget. Pay attention to the Qt::NoFocus option. I don't think it prevents mouse clicks on your widget, but you'll want to test to be sure.
Thank laura and cjhuitt, your responses give me a big hint to solve my question.
Because InputWidget and ButtonWidget are two independent widgets, if we want to deal with the focus issue between them, we need a "global" control, i.e., use QApplication to do the focus job.
The key point is using QApplication's "focusChanged" slot and QWidget's "activateWindow". The following is my modification.
main.cpp
#include "InputWidget.h"
#include "ButtonWidget.h"
#include <QApplication>
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
InputWidget *inputWidget=new InputWidget();
ButtonWidget *buttonWidget=new ButtonWidget(0,&app);
inputWidget->show();
buttonWidget->show();
int ref=app.exec();
inputWidget->deleteLater();
buttonWidget->deleteLater();
return ref;
}
ButtonWidget.h
#include <QWidget>
#include <QPushButton>
#include <QApplication>
#ifndef _ButtonWidget_H_
#define _ButtonWidget_H_
class ButtonWidget:public QWidget
{
Q_OBJECT
public:
ButtonWidget(QWidget *parent=0,QApplication *app=0);
private:
QPushButton *selectedBtn;
public slots:
void changeBtnText();
void changeFocus(QWidget *oldWidget,QWidget *curWidget);
};
#endif
ButtonWidget.cpp
#include "ButtonWidget.h"
#include <QPushButton>
#include <QVBoxLayout>
ButtonWidget::ButtonWidget(QWidget *parent,QApplication *app):QWidget(parent)
{
//selectedBtn setup
selectedBtn=new QPushButton(tr("Click Me!!"),this);
connect(selectedBtn,SIGNAL(clicked()),this,SLOT(changeBtnText()));
//main layout
QVBoxLayout *mainLayout=new QVBoxLayout(this);
mainLayout->setContentsMargins(1,4,1,1);
mainLayout->addWidget(selectedBtn);
setLayout(mainLayout);
//deal with focus
connect(app,SIGNAL(focusChanged(QWidget*,QWidget*)),this,SLOT(changeFocus(QWidget*,QWidget*)));
}
void
ButtonWidget::changeBtnText()
{
selectedBtn->setText("I am clicked :)");
}
void
ButtonWidget::changeFocus(QWidget *oldWidget,QWidget *curWidget)
{
if(oldWidget && curWidget==this)
oldWidget->activateWindow();
}
InputWidget.cpp and InputWidget are not modified.
This solution can work in this example, but I am not sure that it can work in two independent Qt programs(they have their own QApplication), especially in Qt Embedded environment. I would continue doing some tests on it. If there are any results, I would also post them here.
Thank for this discussion, I have learned a lot and thank you all again!!