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.
Related
I do need to invoke a method from my MainWindow class, that inherit from QMainWindow class from a class outside MainWindow, something like this:
Q_ASSERT(QMetaObject::invokeMethod(mainWindow, "attachmentDownloadComplete"));
mainWindow is of class MainWindow : public QMainWindow type
the error is:
no matching function for call to 'QMetaObject::invokeMethod(MainWindow*&, const char [27])'
Q_ASSERT(QMetaObject::invokeMethod(mainWindow, "attachmentDownloadComplete"));
My question is how can I manage to call invoke this method?
The problem is, the slot you are trying to invoke has an input argument.
When you have an input argument you need to specify the argument with Q_ARG.
ex:
In my main window I have a slot, as shown below.
public slots:
void doSomeTest(const char* name) { std::cout << "testing Something"; }
In some other file when invoking it, should do as said below.
Tested and working as expected.
QMetaObject::invokeMethod(mainWin, "doSomeTest", Q_ARG(const char*, "test test"));
First parameter - Your main window object.
Second parameter - The slot name.
From third on all your input parameters with types.
If you have any return type use
Q_RETURN_ARG(RETURN_TYPE, RETURN_VALUE_PARAMETER),
I have the following classes:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QStringList pluginsToStart, QWidget *parent = 0);
~MainWindow();
// some other stuff
public slots:
void on_timeDataChanged(logging::TimeValueVector<bool>& aData);
void on_importStarted();
}
and
class DataImporterWidget : public PluginWidget
{
Q_OBJECT
public:
explicit DataImporterWidget(QWidget *parent = 0);
~DataImporterWidget();
void initConnections(QMap<QString, PluginWidget*> pluginWidgetMap);
in the method initConnections, I want the widget to init the signal-slot connections like so:
void DataImporterWidget::initConnections(QMap<QString, PluginWidget*> pluginWidgetMap)
{
for(Importer* importer : this->getImporterMap().values())
{
connect(importer, SIGNAL(signal_timeDataChanged(logging::TimeValueVector<bool>&)),
parentWidget(), SLOT(on_timeDataChanged(logging::TimeValueVector<bool>&)));
}
connect(this, SIGNAL(signal_importStarted()), parentWidget(), SLOT(on_importStarted()));
}
Importer is a QGroupBox and a base class for derived sub classes specifying concrete data importer types.
It works like so: If I press a button, an DataImporterWidget is created and added to a QMdiArea as a QMdiSubWindow. When creating the DataImporterWidget I call the initConnections() method which sets up the signal-slot connections.
Now, when I run the program, I get the following message:
QObject::connect: No such slot
QMdiSubWindow::on_timeDataChanged(logging::TimeValueVector<bool>&) in src/dataimporter/DataImporterWidget.cpp:81
QObject::connect: No such slot QMdiSubWindow::on_importStarted() in src/dataimporter/DataImporterWidget.cpp:85
QObject::connect: (sender name: 'DataImporterWidget')
I do not understand why I get it because the slot is there. Even if I cast the parentWidget to the MainWindow, I get the same error.
PluginWidget is just a base class deriving from QWidget that holds some common functionality for my used plugins.
I put Q_OBJECT on each base and derived class but still get this error. However, if I set up the connections in the MainWindow, it works just fine, but I wonder why the above solution won't work.
Don't create the connection from child object, instead create it from parent object code after creating the child object.
This way you won't need to cast any type.
You did not shown a huge chunk of important code (like creating DataImporterWidget, setting MainWindow as its parent, the place where you call initConnections...). However, you said
If I use the new signal slot syntax, my program crashes with a
segmentation fault...
If it crashes, than you have to find a reason why. Using old signal-slot connect syntax does not cure the disease, it just delay its manifestation. According to this, the reason why you get a segfault can be parentWidget() == nullptr or parent is not initialized yet.
My advice, check your code, and make user the parent of DataImporterWidget is created and specified before your call initConnections().
I've found the problem. The reason is, that the MainWidget class holds a QMdiArea where I add my PluginWidgets. So, when I create the PluginWidget, I set the MainWidget as its parent, but as soon as I add it to the QMdiArea, it also becomes a child of QMdiSubWindow. The parentWidget was never null but it was the wrong one ...
I have a model that is being displayed in a set of widgets using a QDataWidgetMapper. One such field is a QComboBox populated by a QStringList of options, but the mapping doesn't seem to work.
QComboBox's user property is the currentText() function, which has no corresponding setCurrentText() function for writing, so the mapping fails with the warning Warning: QComboBox::setProperty: Property "currentText" invalid, read-only or does not exist.
Therefore, I created a simple custom QComboBox like the following:
class MappingComboBox : public QComboBox
{
Q_OBJECT
public:
Q_PROPERTY(QString mappingText READ currentText WRITE setCurrentText USER true)
explicit MappingComboBox(QWidget *parent = 0) : QComboBox(parent) {}
QString currentText() const { return QComboBox::currentText(); }
public slots:
void setCurrentText(const QString& s) { setCurrentIndex(findText(s); }
};
But I still get the same mapping error Warning: QComboBox::setProperty: Property "currentText" invalid, read-only or does not exist. I'm quite certain that I have promoted my widgets to be MappingComboBoxes, yet the QDataWidgetMapper still appears to be using the default read-only user property currentText instead of the writable custom user property mappingText.
Am I missing something? Can you not override an inherited class's user property?
Edit: I recognize that this issue is fixed in Qt 5.3.1, but I'm stuck in Qt 4 for the time being so I'm trying to come up with a workaround that doesn't involve editing the source.
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).
I'm trying to send a QStandardItemModel-derived object to PythonQt, but I'm a little confused on how it needs to be sent. When I was using boost::python I had several controls like boost::noncopyable to ensure I wasn't recreating this object, but sharing it with python. I also had constructs to provide a boost shared pointer to python from inside python.
class Scene : public boost::enable_shared_from_this<Scene>, public QStandardItemModel
In PythonQt, however, I'm not sure what's available. The function call takes a QVariantList for all the function parameters.
QVariant PythonQt::call(PyObject* object, const QString &callable, const QVariantList &args = QVariantList))
What I'm confused about now is how to get my object to python via a QVariant. Since its derived from QStandardItemModel, I figured it would already be register
void MyObject::someFunction(QString fileName)
{
QVariant myObjectV = qVariantFromValue(this);
// send to python
...
}
But this gives me the following error:
'qt_metatype_id' : is not a member of 'QMetaTypeId<MyObject>'
I've tried registering it after I declare my class, but this throws a different error.
class MyObject : public QStandardItemModel
{
Q_OBJECT
...
};
Q_DECLARE_METATYPE(MyObject)
QStandardItemModel::QStandardItemModel(const QStandardItemModel&) is private within this context.
I actually get the error twice--once in header where I add the Q_DECLARE_METATYPE and in another header, which has a class which always derives from QStandardItemModel but is otherwise unrelated.
Is Q_DECLARE_METATYPE even the correct way to go about converting this object to a QVariant?
BOOST_PYTHON_MODULE(scene)
{
class_("Scene");
}
Yes, by default, QVariant can take one of te following types - http://doc.qt.io/qt-4.8/qvariant.html#Type-enum - and they are not enough for your task. You should declare additional types by yourself via qmetatype system. Thus you shoud call qRegisterMetaType() function.