Hi i have made a gui in qt4 designer and want to add custom slots with custom class.
It project compiles nicely without errors but my custom function wont work what am i doing wrong? I will show u the header file qt4 designer made for me and ill show u my custom file as well as the main.cpp.. first the main.cpp
I have revised my code, here is what i have now i have added a file called sweetest.cpp and edited the sweetest.h here are my new file and the error i recieve..
First main.cpp
#include "ui_sweetguiform.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *widget = new QWidget;
Ui::SweetGuiForm ui;
ui.setupUi(widget);
widget->show();
return app.exec();
}
now my custom header file sweetest.cpp
#include "sweetest.h"
// trying to include the .moc file wouldnt work at all.
now the sweettest.h file with my code
#include "ui_sweetguiform.h"
class SweetGuiForm : public QWidget
{
Q_OBJECT
public:
SweetGuiForm( ): ui( new Ui::SweetGuiForm )
{
ui->setupUi( this );
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(on_buttonBox_accepted()));
}
public slots:
void on_buttonBox_accepted()
{
ui.textEdit->setText(QString::number(23));
}
protected:
Ui::SweetGuiForm* ui;
};
Here is the compile error i recieve.. I am really stuck
In file included from sweetest.cpp:1:
sweetest.h: In member function ‘void SweetGuiForm::on_buttonBox_accepted()’:
sweetest.h:16: error: request for member ‘textEdit’ in ‘((SweetGuiForm*)this)->SweetGuiForm::ui’, which is of non-class type ‘Ui::SweetGuiForm*’
make: *** [sweetest.o] Error 1
I think im getting closer
The way that signals and slots work is that you must connect a signal to a slot. In your code, the simplest way to do that is in the constructor for the SweetGuiForm. You need to add:
SweetGuiForm() : ui(new Ui::SweetGuiForm) {
ui->setupUi(this);
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(on_buttonBox_accepted()));
}
When the buttonBox emits its accepted signal all slots connected to it will be called.
update 1
On further inspection of your code, you are also missing the Qt macros that are used by the Qt MOC (meta-object compiler) system (http://qt-project.org/doc/qt-4.8/moc.html):
class SweetGuiForm : public QWidget
{
Q_OBJECT
public:
...
};
You also have to push the code through the MOC tool. It will generate a source file that needs to be included in your source. As I recall, you must include that in a cpp file; inclusion in a header is problematic. The following should be sufficient:
sweetguiform.cpp:
#include "suiteguiform.h"
#include "sweetguiform.moc"
update 2
On further further reflection, I had forgotten about the automatic signal/slot connection feature when you name your slots using special names (such as on_buttonBox_accepted). There is a blog post on just that here: http://qtway.blogspot.com/2010/08/automatic-connections-using-qt-signals.html. I've not used it myself, so I can't comment on its ability to work when using a ui member variable, though I suspect that it does not work in that arrangement. Regardless, you still need the Q_OBJECT macro and MOC.
Ok guys i figured it out and thought ide share what i found.
First the documentation is excellent in qt4 use it.
I found you can use qt4 designer to generate the hearder files, first i complied it with out custom slots and generated the ui_sweetgui2.h, then i could open the sweetgui2.h file generated by the first compile i did delete what qt4 put in there and put my custom slots in at that stage. did my head in for hours.... days.
so here is the simplest app on earth but its got me started so here are the files and code that worked for me and the documentation basically got me to click on to whats going on.
main.cpp
Strait from the documentation just changed the class name "SweetGuiForm".
#include <QApplication>
#include "sweetgui2.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SweetGuiForm sweetgui;
sweetgui.show();
return app.exec();
}
next sweetgui2.cpp
My first attempt at c++.. ugly but works. But again i found everything about getting the text from the textEdit and type casting it to a int in the calculator example and searching for toPlainText() in the qt4 assistant. notice below im including the file that i will define the new slots that ill show further on in my explanation. hope im making sense.
#include <QtGui>
#include "sweetgui2.h"
SweetGuiForm::SweetGuiForm(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
void SweetGuiForm::on_buttonBox_accepted()
{
QString stringamount = ui.textEdit->toPlainText();
int digitamount = stringamount.toInt();
ui.textEdit->setText(QString::number(25 + digitamount));
}
next sweetgui2.h the one we included above My custom header file with my custom slot.... simple as i said from the calculator example and twisted a lil.. you will get it this is not what it looks like when you generate it from designer on the first compile this is after i have deleted nearly all what was there and opened the calculator example and followed in the tutorial wich shows you how to make your first custom slot .
#ifndef SWEETGUI2_H
#define SWEETGUI2_H
#include "ui_sweetgui2.h"
class SweetGuiForm : public QWidget
{
Q_OBJECT
public:
SweetGuiForm(QWidget *parent = 0);
private slots:
void on_buttonBox_accepted();
private:
Ui::SweetGuiForm ui;
};
#endif // SWEETGUI2_H
Again Straight from the documentation. I used the calculator example to get the basic flow.
next ui_sweetgui2.h
I include this file because i was trying to add my slots to the sweetgui2.h that was generated by qt4 desinger. doesnt work guys ..so i compiled first with sweetgui2.h file you generate with the designer, i go to forms menu then view code that is where u can save header files. then of course save the ui file.
and compile then you end up with the ui_sweetgui2.h file wich looked like the sweetgui2.h generated by the designer
#ifndef UI_SWEETGUI2_H
#define UI_SWEETGUI2_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QDialogButtonBox>
#include <QtGui/QHeaderView>
#include <QtGui/QTextEdit>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_SweetGuiForm
{
public:
QDialogButtonBox *buttonBox;
QTextEdit *textEdit;
void setupUi(QWidget *SweetGuiForm)
{
if (SweetGuiForm->objectName().isEmpty())
SweetGuiForm->setObjectName(QString::fromUtf8("SweetGuiForm"));
SweetGuiForm->resize(486, 238);
buttonBox = new QDialogButtonBox(SweetGuiForm);
buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
buttonBox->setGeometry(QRect(150, 200, 181, 26));
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
textEdit = new QTextEdit(SweetGuiForm);
textEdit->setObjectName(QString::fromUtf8("textEdit"));
textEdit->setGeometry(QRect(150, 50, 221, 91));
retranslateUi(SweetGuiForm);
QObject::connect(buttonBox, SIGNAL(rejected()), SweetGuiForm, SLOT(close()));
QMetaObject::connectSlotsByName(SweetGuiForm);
} // setupUi
void retranslateUi(QWidget *SweetGuiForm)
{
SweetGuiForm->setWindowTitle(QApplication::translate("SweetGuiForm", "SweetGuiBack", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class SweetGuiForm: public Ui_SweetGuiForm {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_SWEETGUI2_H
Then i recompiled again with my custom slots and shazam! now i can begin to learn some c++.
thanks for all the hints guys, between you all and the documentation i got there.
hope this helps. The main thing to look at is the order things are included i mean my sweetgui2.cpp file
includes the sweetgui2.h file. wich grabs all my custom stuff.
My sweetgui2.h file
includes the ui_sweetgui2.h wich has all the stuff the designer made when i did the first compile. Main.cpp calls my SweetGuiForm class .
As you all can see my first couple days with c++ but this is a good starting point. it made me put the basic flow together in my mind. qt4 assistant look at it.. its well explained and the examples seem very good. ho ho ho merry xmas. hope my explanation helps.
Related
I wrote a little program with a my own class within the main.cpp. Here the code:
#include <QApplication>
#include <QPushButton>
#include <QLabel>
class MyWidget : public QWidget {
//Q_OBJECT
public:
MyWidget(QWidget* parent = 0);
QLabel* label;
QString string;
signals:
public slots:
void setTextLabel();
};
void MyWidget::setTextLabel() {
label->setText("Test");
}
MyWidget::MyWidget(QWidget* parent)
: QWidget(parent) {
}
int main(int argc, char** argv) {
QApplication app(argc, argv);
MyWidget widget;
widget.show();
return app.exec();
}
it seems work but not "completely". My slot doens't work. I suppose i have to put Q_OBJECT. BUT, doing so, I got a list of errors, like this:
undefined reference to `vtable for MyWidget'
........................................
collect2: error: ld returned 1 exit status
make: *** [mywidget] Error 1
I can I manage that? Where the problem?
Signals and slots in Qt are managed through the moc: meta object compiler. Basically, the moc generates additional C++ code for each class containing the Q_OBJECT macro in order to implement effectively the signals and slots mechanisms. The additional code is then linked to the original class declaration.
The problem here is that your class is declared in main.cpp: this conflicts with how the moc is working with your code. You should declare your class in a separate header.
More about the moc
Edit: as hyde pointed, an alternative is to include in your cpp the file generated by the moc: Why is important to include “.moc” file at end of a Qt Source code file?
just append the line #include"main.moc" to your cpp source file should be enough.
More information:
Why is important to include ".moc" file at end of a Qt Source code file?
I am having a hard time subclassing Widgets in the QDesigner. I am using QDesigner to create my UI, but using cmake to compile rather than .pro files. So I am basically using QT Creator for nothing other than generating ui files.
Now I want to subclass QLabel in order to override the mouse click event, so as far as I understand all I have to do is right click the QLabel and select "promote to". It then asks me what i want to promote to, so I say "clickable_qlabel.h". However, when I call "make", I get "ui_mainWindow.h:95:5: error: ‘Clickable_QLabel’ does not name a type". Unfortunately I have no idea where I need to put clickable_qlabel.h, or whether it already exists and I just need to fill it with my code.
Any help would be greatly appreciated!
Many thanks.
[UPDATE]
OK, so now I have created the following class:
QLabelClickable.h
#ifndef _QLABELCLICKABLE_H_
#define _QLABELCLICKABLE_H_
#include <QLabel>
#include <QMouseEvent>
class QLabelClickable : public QLabel
{
Q_OBJECT
public:
explicit QLabelClickable( const QString& text="", QWidget* parent=0 );
~QLabelClickable();
signals:
void clicked(int, int);
protected:
void mousePressEvent(QMouseEvent* event);
};
#endif
QLabelClickable.cpp
#include "QLabelClickable.h"
QLabelClickable::QLabelClickable(const QString& text, QWidget* parent)
: QLabel(parent)
{
setText(text);
}
QLabelClickable::~QLabelClickable()
{
}
void QLabelClickable::mousePressEvent(QMouseEvent* event)
{
emit clicked(event->x(),event->y());
}
So this code compiles beautifully. So now I am in QtDesigner and I create a QLabel, called label4, and I right click and select "Promote to". Then under "Promoted class name:" I type "QLabelClickable" and under "Header file:" I type "QLabelClickable.h". Then I click "Promote". Wonderful. But I am still getting the error:
Vigil/build/ui_mainWindow.h:328:42: error: no matching function for call to ‘QLabelClickable::QLabelClickable(QWidget*&)’ label_4 = new QLabelClickable(tab);
So clearly QtDesigner needs to be instructed (somehow) where my implementation of QLabelClickable is. Quite frustrating.
Eh. My error, I should have read the error message properly. I hadn't included a constructor for the passing of only a QWidget. Adding
QLabelClickable::QLabelClickable( QWidget* parent ) : QLabel(parent) {
}
to my CPP has solved the problem! Hooray.
I have wrote an app which mainly is an equivalent to mac osx finder. When copying file into a folder, I'm checking if a file of the same name already exist. In case it exist, I'm asking the user if he want to cancel, overwrite or not overwrite.
The Dialog box for the overwrite has been created with QT designer and generate a dialogoverwrite.ui, .cpp and .h.
User Interface
dialogoverwrite.cpp
#include <QDialogButtonBox>
#include "dialogoverwrite.h"
#include "ui_dialogoverwrite.h"
DialogOverwrite::DialogOverwrite(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogOverwrite)
{
ui->setupUi(this);
}
DialogOverwrite::~DialogOverwrite()
{
delete ui;
}
dialogoverwrite.h
#include <QDialog>
#include <QDialogButtonBox>
namespace Ui {
class DialogOverwrite;
}
class DialogOverwrite : public QDialog
{
Q_OBJECT
public:
explicit DialogOverwrite(QWidget *parent = 0);
~DialogOverwrite();
private:
Ui::DialogOverwrite *ui;
};
I'm using this class in My TreeWidget application as shown below, I will only add the required code
DialogOverwrite *OverwriteDialog = new DialogOverwrite;
OverwriteDialog->exec();
A kind of OverwriteDialog.button.value could be perfect for me.
the exec will show the dialog and wait for a user action. How can I easily catch the return value : Cancel, Yes, YesToAll, No, NoToAll
I'm looking for an easy to get it. I would like to avoid any additional method in the dialogoverwrite class with signal/connecT. I really just need the button value to react.
Thanks a lot
Call QDialog::done(int r) with a value that represents one of the closing buttons. This value is returned by exec().
Default values are provided by QDialog::DialogCode enum.
I'm working with Qt, using the latest version of Qt Creator on windows 8.1. Once I finished my GUI, I tried to communicate some of my QML elements in C ++ and vice versa, i.e. send data from the two sides.
Example I've tried
I had no idea how to do this, then I have forwarded to read the official documentation and examples from this site, but no one works for me.
Code:
#include <QQmlApplicationEngine>
#include <QDebug>
#include <QObject>
#include <QGuiApplication>
#include <QQuickView>
class MyClass : public QObject
{
Q_OBJECT
public slots:
void cppSlot(const QString &msg) {
qDebug() << "Called the C++ slot with message:" << msg;
}
};
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
QObject *item = view.rootObject();
MyClass myClass;
QObject::connect(item, SIGNAL(qmlSignal(QString)),
&myClass, SLOT(cppSlot(QString)));
view.show();
return app.exec();
}
But i'm getting an error:
C:\Users\Tomi\qml\main.cpp:20: error: cannot convert 'QQuickItem*' to 'QObject*' in initialization
QObject *item = view.rootObject();
What I want
All I need is that when a button is pressed from QML, certain data to C++ are requested and when they are ready to be sent to QML. Is this possible?, could you show me a simplistic and functional example?
Thanks!
The error is because the compiler isn't aware of what a QQuickItem is. You need to include it:
#include <QQuickItem>
QQuickItem is only forward-declared in QQuickView's header, for example, so you can't rely on it to include QQuickItem for you, and shouldn't anyway.
Also, the comment about moc not working with classes defined in main.cpp is wrong; you just need to include main.moc after your class definition for the QObject stuff to work:
#include "main.moc"
I dislike this myth, because it turns short snippets and examples into three files, when they could be contained in just one, which is much more useful on Stack Overflow, bug trackers, etc. :)
In my project, I have made a GUI program that will occasionally send commands to a cli program. I do it like this:
system("folder\\program.exe -d folder\\inputFile.dat folder\\outputPath");
Obviously without those names but you get the idea. This works fine, except when my GUI program sends these commands, a command prompt window opens and does whatever the cli program is supposed to do. It looks very bad and unclean.
Is there any way I could "hide" the cli program window but still have it silently do what it needs to do?
Thanks for your time :)
EDIT: I tried olive's technique which was to use QDesktopServices and QUrl to call the program:
QDesktopServices::openUrl(QUrl("folder\\program.exe -d folder\\inputFile.dat folder\\outputPath"));
The console window isn't showing up, however, the program wasn't called at all. Are there any changes that need to be made to the path when using olive's technique rather than my original system() command?
I cannot determine whether you need a cross platform solution or not. On windows execution using start generally hides the command window.
system("start program.exe -d inputFile.dat outputPath");
I solved this problem like so:
QProcess::execute("start program.exe -d inputFile.dat outputPath");
The problem is, I can only do this once. Everytime I try to call it again, it will not work. The thing that makes this hidden is "start." Taking it out allows the console to be seen, it's just blank.
It seems like I need a way to "end" the program or whatever before running it again. (I say or whatever because I have no clue what/why adding "start" to the path does)
QDesktopServices::openUrl() is usually used if you wish to open a document (eg PDF document, web page) in a viewing or editing program and you're not sure which programs have been installed. This function lets the operating system choose for you from the list of default programs with respect to the file types.
Although you can also use the function to open executable files (eg console programs), an alternative to that would be using QProcess. If you don't need to communicate with the console program or wait for it to complete, you can just launch it in a fire-and-forget fashion using one of the two QProcess::startDetached() static functions
QProcess::startDetached
Sorry for misleading with QDesktopService::URL, later i understood that it wont accept parameter.
So implemented by improving error handling, if process not started/exited badly or waitfor the process to finish the task..I think this is useful
In QProcess, execute is blocking thread, but start is resuming the thread.
Current code is using start() API, but more or less featurewise like execute..
Code is copied from SO and modified little for the current requirements.
> Mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QShortcut>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
cameraControl = new QProcess(this);
}
MainWindow::~MainWindow()
{
delete ui;
cameraControl->close();
delete cameraControl;
}
void MainWindow::on_pushButton_clicked()
{
// connect the camera control finished signal to the slot that will read the exit code and
// place the std output string from the process into a label on the form
connect(cameraControl, SIGNAL(finished(int , QProcess::ExitStatus )),
this, SLOT(on_cameraControlExit(int , QProcess::ExitStatus )));
// Disable the ui button do we don't get double presses
ui->pushButton->setDisabled(true);
// setup the gphoto2 arguments list
QStringList args;
args.append("d:\\text.txt");
// start the camera control
cameraControl->start("notepad",args);
// // wait for the process to finish or 30 seconds whichever comes first
cameraControl->waitForFinished(30000);
}
void MainWindow::on_cameraControlExit(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << cameraControl->errorString();
qDebug() << cameraControl->readAllStandardError();
qDebug() << cameraControl->readAllStandardOutput();
ui->pushButton->setEnabled(true);
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QProcess>
#include <QObject>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void reply2();
private slots:
void on_pushButton_clicked();
void on_cameraControlExit(int exitCode, QProcess::ExitStatus exitStatus);
private:
Ui::MainWindow *ui;
QProcess* cameraControl;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
in your Qt program,there is a .pro file.You can add this line into the file:
config+=console