I want to use the elements of an enum as items in a QComboBox. I can do so if the enum is defined in the same class but I would like to use an enum defined in a header file. My goal is to use the enum directly from the header file, without altering the header file. Moreover, I would like my code to adapt to a changing enum, both in the name of the elements and in the number of them.
I have found this answer and this link that have helped me understand how to populate a QComboBox with an enum. The solution in the answer works for me but only if the enum is defined in the class.
The basic code I would like to implement looks like:
definitions.h
#ifndef _DEFINITIONS_H_
#define _DEFINITIONS_H_
typedef enum
{
FIRST = 0,
SECOND,
THIRD
} elements;
#endif
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "definitions.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
Q_ENUMS(elements);
public:
explicit MainWindow(QWidget *parent = 0);
QComboBox *comboBox;
};
#endif
mainwindow.cc
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
{
int index = metaObject()->indexOfEnumerator("elements");
QMetaEnum metaEnum = metaObject()->enumerator(index);
for (int i = 0; i < metaEnum.keyCount(); i++)
comboBox->addItem(metaEnum.valueToKey(i));
}
This code does not encounter any issue at compilation on runtime but has no effect at all. Defining the enum in MainWindow class works like a charm.
It does not look like a visibility issue because I can use the elements of the enum in my code and I have not encountered any compilation problem.
I have tried redefining my enum in mainwindow.h with typedef without success:
typedef elements new_elements
I have also tried replacing Q_ENUMS with Q_ENUM as suggested by the answer below but the result is the same.
Is it possible to use Q_ENUMS/Q_ENUM with an enum defined in a header file?
What should I do different?
You can't do that. Q_ENUMS need a meta object provided either by the QObject class or the Q_GADGET macro, that's why it works when the enum is declared in a class derived from a QObject.
Since Qt 5.8, a new macro was introduced Q_ENUM_NS that makes this possible:
This macro registers an enum type with the meta-object system. It must be placed after the enum declaration in a namespace that has the Q_NAMESPACE macro. It is the same as Q_ENUM but in a namespace.
You can do something like that:
namespace MyNamespace {
Q_NAMESPACE
enum elements {
FIRST = 0,
SECOND,
THIRD
};
Q_ENUM_NS(elements)
}
See this post for more information.
Updates
Regarding the last comment, you can create a new enumeration and associate each element with the value of the new one.
class MainWindow : public QMainWindow {
Q_OBJECT
public:
enum elements {
FIRST = ::elements::FIRST,
SECOND = ::elements::SECOND,
THIRD = ::elements::THIRD,
};
Q_ENUM(elements);
}
Then, for a function like:
void use_enum(elements e);
// Call it with the original one
use_enum(elements::FIRST);
// Call it with the new one, you just created
use_enum(MainWindow::elements::FIRST);
Check the Q_ENUM that registers automatically as metatype as it is said in the documentation What's New in Qt 5.5:
Added Q_ENUM to replace Q_ENUMS, which allows to get a QMetaEnum at compile time using QMetaEnum::fromType. Such enums are now automatically registered as metatypes, and can be converted to strings within QVariant, or printed as string by qDebug().
Related
I have eight list widgets in a tab widget. They have similar names, and Designer's "Go to slot" mechanism has made links to slots it names (in the "private slots" section of "mainwindow.h") like:
void on_SR0listWidget_itemClicked(QListWidgetItem *item);
I saw warnings that "Slots named on_foo_bar are error-prone," and now I need to change their names in order to discover if that's the cause of the weird behaviour I'm getting.
I tried simply refactoring the names, but that stopped the slot code from working. I used Designer's graphical "Edit Signal/Slot" mechanism and was able to connect a newly added list widget's "itemClicked(QListWidgetItem *item)" signal to a newly added slot, and it looks OK in the graphical representation, but there's no debug message (that I set up in the Slot function) when an item is clicked.
I also use those widgets' "entered" signals, so there will be at least 16 to fix. I would write a script if it could be done by parsing the relevant files.
One example of exactly how to rename one of my replacement slots and connect an "item clicked" or "entered" signal to it (and where it should go) would be a great help.
Signals/slots setup through the designer rely on the names of the widgets involved. This can lead to problems if the widget names are changed. There are times when using the designer method will lead to code that compiles but doesn't actually make the connections you expect. This is why you are getting that warning.
You can get more reliable behavior by connecting the signals and slots programmatically. For example, let's say you have a class header such as:
#include <QMainWindow>
namespace Ui {
class MyWindow;
};
class QListWidgetItem;
class MyWindow : public QMainWindow {
Q_OBJECT
public:
explicit MyWindow(QWidget* parent = nullptr);
~MyWindow() override;
private:
void handleItemClicked(QListWidgetItem* item); // this is your slot
Ui::MyWindow* ui;
};
You can connect the signal/slot together in the cpp file like this:
#include "MyWindow.h"
#include "ui_MyWindow.h"
#include <QDebug>
MyWindow::MyWindow(QWidget* parent)
: QWidget(parent),
ui(new Ui::MyWindow()) {
ui->setupUi(this);
// connect() has many overloads, but in this case we are passing:
// 1. the object emitting the signal
// 2. the signal being emitted
// 3. the object whose slot we want to call
// 4. the slot to connect to
connect(
ui->listWidget, &QListWidget::itemClicked,
this, &MyWindow::handleItemClicked);
}
MyWindow::~MyWindow() {
delete ui;
}
void MyWindow::handleItemClicked(QListWidgetItem* item) {
qDebug() << "item clicked";
}
You can still use the designer to layout your UI - but prefer to manage connections directly in code rather than through the designer.
I will have a rather large amounts of enums to be used in Qt c++ frontend, QML and also in c++ backend with no Qt libraries.
I am presenting two ways to do this, both works runtime. The funny thing is moc file generated for both solutions are identical. What is the QML engine use to lookup its QT_ENUMs if the MOC files alone aren't sufficient?
Therefore i make a header file with those enums defined and include the file "inline" to make sure it is part of the class. This works, but autocomplete in QML is missing (need to alt-tab back and forward and loose efficiency)
#include <QObject>
class ButtonEnums : public QObject
{
Q_OBJECT
public:
ButtonEnums(QObject* parent = nullptr);
#include "backend/app/messages_frontend.h"
Q_ENUM(EnTaskSelection)
};
Now i have to remember copy paste and get a larger header file then desired if i do this, but autocomplete in QML works:
#include <QObject>
class ButtonEnums : public QObject
{
Q_OBJECT
public:
ButtonEnums(QObject* parent = nullptr);
enum EnTaskSelection {
TASK_ONE = 0, //Strict indexes defined by main menu
TASK_TWO,
TASK_THREE,
TASK_FOUR
};
Q_ENUM(EnTaskSelection)
};
I am building a notepad and want to count the words in a dialog.
QString input = ui->textEdit->toPlainText();
int spaces = input.count(" ");
ui->NumWordsLabel->setNum(spaces);
This is my attempt so far.
However, I want to execute this code in my dialog so I need to pass the
ui->textEdit->toPlainText()
Into my dialog.
This is how I create my dialog...
void MainWindow::on_actionWord_Count_triggered()
{
word_count = new Word_count();
word_count->show();
}
How would I get the required information into the dialog?
Thanks.
Generally you can pass constructor arguments to pass data to your classes. For example:
Header file:
class Word_count : public QDialog
{
Q_OBJECT
public:
explicit Word_count(QString text, QObject *parent = 0);
...
}
Source file:
Word_count(QString text, QObject *parent)
: QDialog(parent)
{
ui->setup(this);
... figure out word count and set labels ...
}
How to use:
void MainWindow::on_actionWord_Count_triggered()
{
word_count = new Word_count(ui->textEdit->toPlainText());
word_count->show();
}
Important notes:
The QObject *parent argument should always be present in the constructor arguments. Make sure to only place the = 0 in the header file, or else you will get an error.
Your constructor should be marked explicit, unless you know you do not want that. Explicit prevents the C++ compiler from automatically casting to your type using a given constructor.
Pass the parent parameter to your inheriting class, whether that be QDialog, QWidget or QObject, using the constructor initializer list syntax. This is done in the source file example with : QDialog(parent).
You can add as many arguments as you need, but they should be before the parent argument. This is because the parent argument has a default value that can be implied. Because you must specify arguments in order, it can not be implied if there are required parameters after it.
This only will work for creating the dialog. If you want the dialog to dynamically update, you'll need to use a slot or method like suggested by others. Alternatively, if you don't want a dynamically updating dialog, consider using exec instead of show so that users must close your word count dialog before continuing with their work.
Add a slot like void setText( const QString& text ) to your Word_count class.
Then, you can emit a signal like void textChanged( const QString& text ) const from your MainWindowclass.
Don't forget to connect both.
I tried to make a class which is a subclass of QEvent, but I got error after building.
My steps,
1. Create a project using Qt console template
2. create the following code
#ifndef MYEVENT_H
#define MYEVENT_H
#include <QEvent>
#include <QObject>
class MyEvent : public QEvent
{
Q_OBJECT
public:
explicit MyEvent();
signals:
public slots:
};
#endif
//CPP File
MyEvent::MyEvent() :
QEvent(QEvent::User)
{
}
moc_MyEvent.cpp:70:21: error: invalid use of non-static data member 'd_ptr'
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
~~~~~~~~~^~~~~
moc_MyEvent.cpp:70:21: error: 'd_ptr' is a protected member of 'QObject'
../../../../../../Qt5.1.0/5.1.0/clang_64/include/QtCore/qobject.h:411:33: note: declared protected here
QScopedPointer<QObjectData> d_ptr;
^
Qt5
Mac OSX 10.8.4
How do I solve it and why? Thanks.
Dcow gives corrent answer.
Your mistake is that QEvent does not inherit from QObject, and you try to do it. You should not use Q_OBJECT macros or you should interhit your class from QObject too. But it's dark side.
First of all WHY? You should write why you need this, I'm sure that your problem solution which you are trying to fix is just wrong!
Secondly problem is Q_OBJECT macro. QEvent is not a QObject so this macro is not applicable and this is why you have this error.
As already pointed out: No Q_OBJECT. But let me add something and point your attention to a rarely used and widely unknown macro: Q_GADGET
Almost a Q_OBJECT for non-QObjects.
From the Qt Docs:
Use Q_GADGET instead of Q_OBJECT to enable the meta object system's
support for enums in a class that is not a QObject subclass. Q_GADGET
makes a class member, staticMetaObject, available. staticMetaObject is
of type QMetaObject and provides access to the enums declared with
Q_ENUMS. Q_GADGET is provided only for C++.
Comes handy from time to time.
I'm implementing a Tetris game. In Qt Designer I drew a Frame widget.
Then I organized a QtGlass inheriting from that Frame. So, in Qt Designer this looks like Object frame with QtGlass class. Now I would like to make the figure move within existing limits (walls etc). I'm trying to implement it like is shown below.
Well, I've come across the fact that I fail to reach my QtGlass object. So, I know that it has a method isMovementPossible(), but I don't know how to use it. My QtGlass instance seems to be called "frame", but if I use this name, I get the error "Unable to resolve identifire frame".
QtGlass.h
#ifndef QTGLASS_H
#define QTGLASS_H
#include <QFrame>
#include "Figure.h"
class QtGlass : public QFrame {
Q_OBJECT
public:
bool isMovementPossible();
protected:
Figure Falcon;
...
}
Figure.cpp
#include "Figure.h"
#include "QtGlass.h"
#include <QtGui>
#include <QtGui/QApplication>
void Figure::set_coordinates(int direction) {
previous_x = current_x;
previous_y = current_y;
switch (direction) {
case 1:
{//Qt::Key_Left:
current_x -= 1;
if (frame->isMovementPossible()) {
break;
}
current_x += 1;
break;
}
...
}
To be accessible within your Figure method the frame variable would have to be either a global variable or a member of your Figure class (or of a superclass).
If you need access to your QtGlass instance within a Figure instance then you will need to pass a reference (or pointer) to it. You can either pass that to the Figure when it is constructed (assuming the frame outlives the figure) or pass it as a parameter to the method that needs it.
For example, if your frame always outlives the figures within it then you could simply do something like
class QtGlass; // forward declare to avoid circular header include
class Figure
{
public:
Figure( const QtGlass& glass ) : frame( glass ) {}
void set_coordinates(int direction) {
// ...
if (frame.isMovementPossible()) {
break;
}
// ...
}
// other methods...
private:
const QtGlass& frame;
// other members...
};
and your QtGlass constructor could do
QtGlass::QtGlass( QWidget* parent )
: QFrame( parent )
, Falcon( *this )
{
}
Alternatively you could have a dedicated setter method for setting the frame on the figure if setting it at construction time is not convenient. The member would need to be a pointer in that case though (although the setter could still pass by reference).