I am unable to find a proper simulation for ItemClicked() SIGNAL for QTreeWidget.
Is there a way to simulate it so that ItemClicked Signal is generated ?
e.g: we can emit ItemClicked in a derived class of QTreeWidget but cannot (as a QT rule) outside of it.
You can't use the emit call for class A to emit class B's signals. But note that the documentation for signals and slots says:
"You can connect as many signals as you want to a single slot, and a signal can be connected to as many slots as you need. It is even possible to connect a signal directly to another signal. (This will emit the second signal immediately whenever the first is emitted.)"
So you can work around this by declaring a signal in class A of the same signature as the one you want class B to emit, and connecting the signals together:
connect(
myclass, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
treewidget, SIGNAL(itemClicked(QTreeWidgetItem*, int))
);
Then emit itemClicked from myclass. If I'm not mistaken, it will work for this case...and fire the treewidget's itemClicked signal for you.
Related
I would like to understand a simple piece of code I came across. It is a connection between an object of the interface and two signals.
The code is:
connect( ui->checkbox_legEnabled,
SIGNAL( stateChanged( int ) ), SIGNAL( edited() ) );
What is the meaning of this line of code?
Thanks,
Sara
With Qt signals and slots, you can directly connect one signal to another signal (or non-signal member function), without having a slot in between. See connection function invoked here is this overload of QObject::connect.
This line of code hence means, whenever the object ui->checkbox_legEnabled (presumably some kind of QCheckbox) emits the stateChanged signal (that has an int parameter passed along), directly emit another signal (or ordinary member function) edited (without parameters).
Short answer is you can connect a signal to another signal and that means that the second signal will also emit whenever the first signal is emitted, read more about signals and slots in the documentation here, also check out the new way to call connect (with function pointers)
Now in your case what it does it's basically allows you to keep the ui private, but in the same time forward the signals you want to the outside of your object, by allowing other objects to connect to the signal(s) you provide in the interface.
Incomplete usage example (based on your code, i named the class that contains your code MyWidget): the main-window (or whoever) that has access to your widget can be notified whenever something changes inside, by connecting to the edited signal:
void MainWindow::createMyWidget()
{
m_myWidget = new MyWidget(this);
connect(m_myWidget, &MyWidget::edited, this, &MainWindow::myWidgetWasEdited));
}
This way whenever something changes inside MyWidget the MainWindow can be notified about the edit and it can take the necessary actions inside the myWidgetWasEdited slot.
This can be expanded, if needed, to provide an signal for each particular "edit" instead of a single generic edited signal (but this depends on your needs).
I know how to call a signal from inside the class where the signal is located: by using emit. But what if I want to call it externally, from the parent object?
The reason why I want to do is is because a given QPushButton is connected to a slot which picks the button that called it by using sender(). Now I want the same functionallity of that slot to be called but not after a manual click in the button, but from within the code itself. Normally I would just programatically call for the slot, but because of the usage of sender(), that way is invalid: calling the slot directly will not give it the id of the button.
So how could I "externally" ask for the object for it to emit one of its signals? That is, how can I make my QPushButton emit its clicked() signal from within the code, not by clicking the button with the mouse?
You cannot emit signal directly from the parent object.
Only the class that defines a signal and its subclasses can emit the signal. (http://qt-project.org/doc/qt-4.8/signalsandslots.html#signals)
You can define a method in your QPushButton emitClicked() where you emit the signal. Then you call emitClicked() on instance of your QPushButton from the code.
The Qt headers contain this interesting line (in qobjectdefs.h):
#define emit
Which means that presence or absence of the emit keyword has no effect on the code, it's only there to make it more obvious to the human reader that you are emitting a signal. That is to say:
emit clicked();
is exactly the same (as far as the C++ compiler is concerned) as
clicked();
Given that, if you want your button to emit its clicked() signal, it's just a matter of doing this:
myButton->clicked();
(although if you wanted to be clever about it, this would work equally well):
emit myButton->clicked();
Seems that Qt Test module is just for this case.
Check out this tutorial on simulating GUI events.
Basically you use QTest::​mouseClick and pass pointer to your push button.
I have some problems with Qt. I have a class with a signal who's parameters are strings, and a slot. I'm connecting the signal to the slot in the class constructor. Also, I'm creating a thread in the class constructor. The thread reads data from a server and updates the UI(emits the UpdateMe signal). This is how I connect the signal to the slot:
QObject::connect(this, SIGNAL(UpdateMe(string, string)), this, SLOT(ModifyUI(string, string)));
I have a QTreeWidget with some file names. When I rename a file I notify the server and the server notifies the other clients. When I connect a single client there is no problem, but when I connect more than one client a problem appears: when I notify the server from the second client(when I write into the socket) the following error appears:
QObject::connect: Cannot queue arguments of type 'QVector<int>'
I tried to register QVector with qRegisterMetaType but I also have a signal that is emited when I modify an QTreeWidgetItem(when I rename the item, for example) and I need to dissconnect this signal when I want to change the item's text. If I register QVector I can't dissconnect this signal and the signal is emited.
When you register the QVector, does your call look like this?
qRegisterMetaType<QVector<int> >("QVector<int>");
Once you make this call, you should be able to emit the QVector type over queued connections.
If I register QVector I can't dissconnect this signal and the signal is emited.
Registering a metatype shouldn't prevent you from disconnecting a signal. It just allows you to queue types that aren't already registered with the meta system.
Most of the time, errors which look like this seem to be a result of mixing up threads, and specifically with this one, in my (limited) experience, a result of attempting to manipulate GUI elements "held" in the GUI thread using commands run a worker QThread.
I say "held" because quite often you get a complaint/error/crash saying something like "QObject: Cannot create children for a parent that is in a different thread." (i.e. the GUI thread).
The solution: from a non-GUI QThread ALWAYS communicate with GUI elements using signals and slots.
As far as the GUI designer, I understand how certain signals affect certain slots and invoke code. Other than that method, I am unsure about how to invoke a slot from a signal.
Take this example:
void QFileDialog::directoryEntered ( const QString & directory ) [signal]
This is a signal. When the directory is entered, I want this to populate a widget QColumnView with the contents of the directory.
How does a non widget signal invoke a slot of a UI widget.
I assume you use connect but the example provided uses two separate objects.
Signals and slots are features of QObject. It works well even for non-GUI code.
Connecting a signal to a slot is always done through the connect function:
connect(myDialog, SIGNAL(directoryEntered(QString)),
this, SLOT(updateColumn(QString)));
here assuming that you have updateColumn() slot in your main object handling the actual UI update of that QColumnView.
I'm trying to use signals and slots to pass information to the GUI thread from another thread, as I can't modify a pixmap from any other thread. I'm encountering a runtime error:
Object::connect: No such signal QThread::image_change(std::string) in visualiser.cpp:33
Judging from this, though I may be wrong, it looks like the signal is being searched for in the wrong namespace, as it is actually defined in Visualiser::image_change().
My code is as follows:
Visualiser.cpp:
QFutureWatcher<void> watcher;
connect(watcher.thread(), SIGNAL(image_change(std::string)), QCoreApplication::instance()->thread(), SLOT(update_image(std::string)), Qt::QueuedConnection);
QFuture<void> update_thread = QtConcurrent::run(this, &Visualiser::update_state);
watcher.setFuture(update_thread);
...
emit(image_change(imageSrc));
...
void Visualiser::update_image(std::string src)
{
QImage image;
image.load(src.c_str());
ui->visualContainer->setPixmap(QPixmap::fromImage(image));
}
visualiser.h:
signals:
void image_change(std::string src);
public slots:
void update_image(std::string src);
Don't pass thread pointers into connect - pass pointers to the sender and receiver of the event (like this). Because you're giving it QThread pointers instead, Qt is looking for those signals and slots in QThread, where they don't exist. If you give it Visualizer pointers instead, Qt will look for those functions in Visualizer, where they really are, and everything will work.
Hope that helps!
The source and the target of the connection are the same object, this, so the connect call should be:
connect(this, SIGNAL(image_change(std::string)), this, SLOT(update_image(std::string)));
Since the signal will be emitted from another thread than the one the Visualizer has an affinity with (see QObject::moveToThread()), the connection with the slot will automatically be queued, and the slot will be executed by the correct thread.
But for queued connection to work, Qt has to store temporarily the parameter until it can actually call the slot, which is done by converting it to QVariant, storing it somewhere, and then reconverting it to the actual type when the receiving thread is ready to execute the slot.
So you need to register std::string to Qt's metatype system with Q_DECLARE_METATYPE or change the signal and slot parameter type to one that is already registered to (like QString or QByteArray).