How to add 2 Images and Text in QListWidget at run time in Qt?
I want to place one image at the beginning of the list and one at the end and text should be soon after my first Image.
itemclicked event
connect(list, SIGNAL(itemClicked()), this, SLOT(clicked(QListWidgetItem *)));
void MyWidget::clicked(QListWidgetItem *item)
{
//code
}
Have a look at the setItemWidget function. You can design a widget (call it MyListItemWidget) that contains two icon labels and a text label, and in its constructor provide the two icons and the text. Then you could add it to your QListWidget. Sample code follows:
QIcon icon1, icon2; // Load them
MyListItemWidget *myListItem = new MyListItemWidget(icon1, icon2, "Text between icons");
QListWidgetItem *item = new QListWidgetItem();
ui->listWidget->addItem(item);
ui->listWidget->setItemWidget(item, myListItem );
You should also take a look at QListView and QItemDelegate which is the best option for designing and displaying custom list items.
EDIT CONCERNING YOUR CONNECTION
When connecting a signal to a slot their signature should match. This means that a slot cannot have more parameters than a signal. From the signals-slots documentation
The signals and slots mechanism is type safe: The signature of a
signal must match the signature of the receiving slot. (In fact a slot
may have a shorter signature than the signal it receives because it
can ignore extra arguments.)
This means that your signal must have the QListWidgetItem * argument in the connection.
connect(list, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(clicked(QListWidgetItem *)))
Related
I am using a qlistwidget as an deligate inside an cell of Qtreeview.
I have written a handler for the double click on item of qtreelist . Double click handler for Qlistview deligate is working fine.
My requirement is that on double click on any item of qlistwidget deligate for qlistwidget closes.
Please suggest what is the exact signal to be used for it.
Slot for double click on qtreewidgetlist item :---
void listWidgetDeligate::onListWidgetItemDoubleClicked(QListWidgetItem * item)
{
// emit signal to close the deligate
}
Double click handler pass an QListWidgetItem argument to the slot.
How can i use this argument to close the delicate means which signal to emit for this ?
If you haven't found any appropriate built-in signals for that widget you can always define your own signal in .h file :
signals:
void closeOnDoubleClick();
If you only need your slot void listWidgetDeligate::onListWidgetItemDoubleClicked(QListWidgetItem * item) to emit another signal and do nothing else, you can just do
connect(<the object of listWidgetDeligate>,
SIGNAL(<signal that was previously connected to slot onListWidgetItemDoubleClicked>()),
SIGNAL(closeOnDoubleClick()));
that means that your listWidgetDeligate will emit signal closeOnDoubleClick() after onListWidgetItemDoubleClicked>() was emitted.
Thus, you do not need a slot.
Remember, that the declared parameters of signal and slot connected to each other must be the same.
I don't know if I can explain this problem without posting reams of code, but here goes.
I have a Qt app which is supposed to display a sequence of images. Each image is displayed in the main Qt window by using a QLabel. To display each image, I wrote a subrotuine called DisplayImg(int i) where the integer i is the frame number. It works for displaying single images.
I then created a 'Play' button (in Qt) which is supposed to play a sequence of images. The Play button is connected to a slot which is named on_Play_clicked(). That is a subroutine which does this:
for (i = 0 ; i < N ; i++)
DisplayImg(i);
The problem is that the display only changes for the final image in the sequence. None of the intermediate images are displayed, even though I know (from printf()) that DisplayImg() is called for all intermediate images.
Is that enough information to explain the problem? Am I misunderstanding how the slot works? Does the main Qt window not update until the subroutine on_Play_clicked() returns?
Yes. Qt performs painting only when the control flow is back in the event loop. You should create a QTimer, connect its timeout signal to a slot and start the timer with desired interval in milliseconds. In the slot you should display the next image, e.g. DisplayImg(i); i++;. Current image number (i) should be stored in a class member variable. When the last image is displayed, stop the timer.
The reason that your images don't appear to be changing on the Qt main window is that you don't have a delay between changing each of your images. If you change your code to something like this, you should get the desired effect:
for (i = 0 ; i < N ; i++)
QTimer::singleShot(5000 * i, this, SLOT(DisplayImg(i))); // sleep 5 seconds and then call display image
You will need to declare your DisplayImage method as a slot in your class like so:
yourclass.h
#include <QtCore>
class YourClass : public QObject
{
Q_OBJECT
private slots:
void DisplayImage(int i);
// private members
// public members
};
Just for completeness. Often for a problem like this QCoreApplication::processEvents() is a solution.
So your code would look like:
for (i = 0 ; i < N ; i++) {
QCoreApplication::processEvents();
DisplayImg(i);
}
BUT... The timer solution is clearly superior to the processEvent solution in this particular case. You just have more control over your display.
I have the following (simplified) code to add QStandardItem's to a QStandardItemModel, attach the model to a QListView, and connect signals of my choice from the model to a function of my choice:
// MyUIContainer derives from QWidget
MyUIContainer::SetItems()
{
// Inside a member function where model/items are added to a QListView...
// This code does not show deletion of existing ItemSelectionModel
QStandardItemModel * model = new QStandardItemModel(ui->listView);
// In the real code, data is set in each QStandardItem
model->setItem( 0, new QStandardItem() );
model->setItem( 1, new QStandardItem() );
model->setItem( 2, new QStandardItem() );
connect(model,
SIGNAL(itemChanged(QStandardItem*)),
this,
SLOT(ReceiveChange(QStandardItem*)));
// I have also tried connecting to this signal - same problem described below
//connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int>)), this, SLOT(ReceiveChange(const QModelIndex &, const QModelIndex &, const QVector<int>)));
ui->listView->setModel(model);
}
MyUIContainer::ReceiveChange(QStandardItem * item)
{
// Problem! This slot is called *three times*
// whenever the check state of an item changes
}
As the code comment indicates, there is a problem: The itemChanged() \ ReceiveChange() signal \ slot combination is called three times whenever the check state of a checkbox in the QListView changes once.
I understand that I can create my own Model class that is derived from QAbstractItemModel, and (if I understand correctly) handle mouse clicks in the view myself, emitting signals such as, for example, the itemChanged signal with a proper user-defined role so that a change in checkbox state can be handled only once.
However, the latter approach requires me to be careful to handle all possible scenarios of mouse clicks & keyboard events that could result in a changed checkbox state. I was hoping, and assuming, that this logic has been handled inside the Qt library itself, so that I don't have to - so that I can simply receive a signal (or some other message) when the check state of a checkbox changes.
Note that it seems that QListWidget (rather than QListView) also has exactly the same problem.
So, my question is: Without writing my own Model class derived from QAbstractItemModel - with its requirement that I myself write code to handle every possible way that a check state can change - how do I capture a changed check state (via a signal or otherwise) such that I can unambiguously capture every time a check state changes once and only once per check state change?
ADDENDUM
With apologies - as I took great care in ruling everything else out - Riateche's comment made it clear to me that the behavior is not supposed to work in the way this question highlighted. Finally, I have indeed tracked down the problem to the fact that I was calling connect() multiple times.
I have a Qt Form that contains 2 combo box messages. The second combobox message depends on the first combo box message. I mean that the dates from the second combobox message depends on the element that I select in the first combobox.
In this moment I have different dates in the first combobox. But the second combobox is not working. I need to creare a connect method or what?
Thx! APpreciate!
Could someone give me a short example?
It's fairly simple. A combobox emits the currentIndexChanged signal that also tells you the new index. Write a method that accepts an integer and changes the second combobox according to the integer (which is the index of the selection in combobox 1).
Here are some code sniplets from a working example.
Method declaration in your window/whatever class header:
public slots:
void setI1(int index);
Filling combobox 1, connecting the signal, e.g. in the constructor:
i1Box->addItem("Neutral", 0);
i1Box->addItem("2,856 K (Illuminant A, light bulb)", 2856);
// ...
connect(i1Box, SIGNAL(currentIndexChanged(int)),
this, SLOT(setI1(int)));
Implementation of the method:
void ViewerWindow::setI1(int index) {
// either use index directly, or, as in this case we have items holding an int:
int i1 = i1Box->itemData(index).value<int>();
// use the value to change second combobox here
}
If it does not work as expected, it is always helpful to print some debug output inside the method that should be called to see where it goes wrong in the chain.
Reference: http://doc.qt.nokia.com/latest/signalsandslots.html
I'm trying to keep track of the textChanged() signal on for handful of QTextEdits. I want to do the same thing regardless of the text edit emitting the signal: uncheck its associated checkbox in a QListWidget if it becomes empty and leave it checked otherwise. The function I have so for is as follows:
void MainWindow::changed()
{
QString tempStr = ui->hNMRedit->toPlainText();
if(tempStr != "")
{
ui->checkList->item(0)->setCheckState(Qt::Checked);
}
else
{
ui->checkList->item(0)->setCheckState(Qt::Unchecked);
}
}
With the current approach, I would have to make a function like this for every QTextEdit; each function containing virtually identical code. If I stored each of the text edits in an array (so I could find their associated index in the QListWidget), would it be possible for me to have a slot like this?
void MainWindow::changed(QWidget *sender) // for whichever text edit emits the
// textChanged() signal
{
QString tempStr = sender->toPlainText();
if(tempStr != "")
{
// I would potentially use some sort of indexOf(sender) function on the array I
// mentioned earlier here... a little new to Qt, sorry
ui->checkList->item(array.indexOf(sender))->setCheckState(Qt::Checked);
}
else
{
// same as above...
ui->checkList->item(array.indexOf(sender))->setCheckState(Qt::Unchecked);
}
}
Is this possible or should I just create a separate slot for every text edit?
Please let me know if any further clarification is needed!
Lastly, I feel like the only meaningful difference between QLineEdits and QTextEdits is the default size. In favor of keeping things consistent, should I just use one of these objects throughout my UI?
Thanks!!!
I think you are missing the point of slots and signals. How are you creating the connections?
Are you trying to check a box when any of the text boxes change? If so use a QSignalMapper to map the textChanged() signals to send a value of true and connect that to the QCheckBox setChecked(bool) slot.
If that is too complicated subclass QCheckBox and create a set of functions checkBox() uncheckBox() so you can toggle states without a variable. Then connect the QTextEdit textChanged() to your subclass checkBox()
If this is not what you are looking for, at least subclass QTextEditto take in a QCheckBox that it can change when the text changes instead of duplicating code for every QTextEdit
All you need is a hash of QAbstractButton*, keyed by QTextEdit*. In the slot, you look up the sender() in the hash, if found you've got the button you need. This is precisely what is done by the QSignalMapper: you can map from a sender QWidget* to your button QWidget*. Use qobject_cast to cast to QAbstractButton*.