Qt4 QMenu items sorting - qt

I am using QT4 and dynamically adding entries to a QMenu. Is it possible to sort the entries in the QMenu without deleting it and creating a new one?
I originally thought there was a function to insert at a specific location so I could sort on insert, but I have not been able to locate it.

Once added, I don't think you can reorder. While you are creating though you could use the QWidget::insertAction method to place it exactly where you want it.
void QWidget::insertAction ( QAction * before, QAction * action )
Otherwise you could use QWidget::addActions. Create your list of Actions and sort it before adding to the QMenu.
void QWidget::addActions ( QList<QAction *> actions )

In one of my codes, I save the QActions into a separate List and generate the menus and submenus on demand. In theory, I can add "weight" to the items and have them re-ordered, but I have not implemented this yet.
Project page is available here: http://code.google.com/p/qtedit4/wiki/qmdilib
Please note that the actions of QWidget (and QMenu) are stored as a QList which can be "read", using QWidget::actions() . Remember that the list is copied, so you can modify the actions but not the list itself. (I hope I am not mistaking...)

Related

Qt - signal for when QListWidget row is edited?

I am working in Qt4.7, and I have a QListWidget in my dialog. I have a QString that needs to match the current text in the row of this widget (the individual rows are editable). Looking at the signals associated with QListWidget, there seem to be signals for when a different index is selected but none for when the text of a the currently selected row changes. I thought currentTextChanged(QString) would do it, but it didn't. I also thought to try to connect each individual row to something, but QListWidgetItem doesn't have any built-in signals. Does anyone know of a way to do this? Thanks!
At first it seems like QListWidget::itemChanged is the way to go, but soon you run into a problem: the signal is sent for everything - inserts, changing colors, checking boxes, and anything else that "changes" the item! Predelnik pointed that out in his answer. Some people have tried to put in flags and filter everywhere by intercepting various signals to find out if editing was the actual event. It gets very messy.
There is also QAbstractItemModel::dataChanged , which would seem like a good solution. It even has a parameter "const QVector& lstRoles" so you could scan for Qt::EditRole and see if it was really edited. Alas, there's a catch - it gets called for everything just like QListWidget::itemChanged and unfortunately, for QListWidget anyway, the roles parameter is always empty when it's called (I tried it). So much for that idea...
Fortunately, there's still hope... This solution does the trick! :
http://falsinsoft.blogspot.com/2013/11/qlistwidget-and-item-edit-event.html
He uses QAbstractItemDelegate::closeEditor, but I prefer using QAbstractItemDelegate::commitData.
So make a connect like so...
connect(ui.pLstItems->itemDelegate(), &QAbstractItemDelegate::commitData, this, &MyWidget::OnLstItemsCommitData);
Then implement the slot like this...
void MyWidget::OnLstItemsCommitData(QWidget* pLineEdit)
{
QString strNewText = reinterpret_cast<QLineEdit*>(pLineEdit)->text();
int nRow = ui.pLstItems->currentRow();
// do whatever you need here....
}
Now you have a slot that gets called only when the list item's text has been edited!
I guess you need to look into the following signal:
void QListWidget::itemChanged(QListWidgetItem * item)
But be careful because it's being sent every time some property of item changed, not only text. I remember when we ran into the problem once when we changed item colors and got tons of false positive slots called because of that. If you need more fine tuning I guess it's better to write model/view classes yourself and not rely on QListWidget.

Is there way to access QAction::data() without using an intermediate QAction group?

When creating dynamic menus, I often need the associated signal to respond to a particular index value (e.g., a database row identifier associated with that menu item). To do this I seem to need to use the code below, which feels like a hack.
QActionGroup *oneOffgroup = new QActionGroup(menu);
QAction *action = new QAction(tr("New text form..."),menu);
action->setData( writingSystem.id() );
oneOffgroup->addAction(action);
connect( oneOffgroup, SIGNAL(triggered(QAction*)), this, SLOT(newTextForm(QAction*)) );
submenu->addAction(action);
This answer suggests using the QMenu::triggered(QAction*) signal. That would just mean that I would have to sort out every signal that was sent to that menu, though. (That would be okay in some contexts, not in the one I am currently working on, though.)

Is it possible to copy QCombobox to another QCombobox

I use Qt Designer to build my UI layout. On the layout, I have a combobox named cb_fac_cd. In my code I have a function that will automatically build a combobox based on the list I'm attempting to build. I have a lot of these lists defined in the database and this function spits out a QComboBox.
Unfortunately, until now I've only used this function to add cellWidgets to QTableWidgets. It works perfectly there. Now I want to populate this preexisting combobox.
It seems that a simple
self.ui.cb_fac_cd = makeComboBox('FACILITIES') doesn't work. I can see that the function returns the QComboBox as usual, but the cb_fac_cd combobox remains unpopulated.
How can I copy or assign the returned combobox to the one build in Qt Designer?
I am using PyQt, but that shouldn't make any difference.
As far as I know, you cannot replace objects which are part of the .h files generated by Qt's UIC mechanism (though I cannot confirm that 100% right now).
What I usually do in such cases is to have an empty layout in the ui file and then do the following:
(Note that I'm using Qt/C++ syntax as I don't know the pyqt syntax but I think you will get the idea)
QComboBox* pNewComboBox = makeComboBox( "FACILITIES" );
ui.pComboBoxLayout->addWidget( pComboBox );
Additionally, if possible for your program, consider using an enumeration rather than a string for your makeComboBox function. This is usually faster and safer.
It sounds like you should either
Change makeComboBox to populateComboBox(QComboBox *p) and pass it the combobox in your layout to fill, or
Create and add the QComboBox to your layout dynamically and remove it from your .ui
You can change the model from you Ui to the one you get from the other combobox:
tempCombo = makeComboBox( "FACILITIES" )
self.ui.cb_fac_cd.setModel(tempCombo.model())
But for that part:
I have a lot of these lists defined in the database and this function
spits out a QComboBox. Unfortunately, until now I've only used this function to add
cellWidgets to QTableWidgets.
If the data comes from a database, you might want to look at QSqlRelationalTableModel to avoid doing that manually.

Populating a QComboBox and a QTable[View|Widget] from javascript

I'm trying to write a script for an application developed with Qt, using javascript for the business logic and a .ui file for the GUI, but I'm facing two problems.
In the ui I declared a QComboBox, to which I successfully connect javascript functions to handle
signals such as editTextChanged, etc. I was wondering I cannot populate the combobox from within
javascript code, because the addItem function is not exposed to script-side code.
combobox.editTextChanged[action](ComboBoxChanged); // OK (action is "connect" or "disconnect")
combobox.addItem("element 1"); // Error!
Is there any (other) way to do this?
I need to show a set of items (strings) in a table-like component. I tried using a QTableView and
QTableWidget but I cannot insert or get items. For example, from javascript I cannot access the
setModel function of a QTableView (if at least I could create a QAbstractItemModel from
script...), neither I can access the item(row,col) function of a QTableWidget class, to set an
item's text. Is there any way to show a table of strings to the user, let edit them and retrieve
the modified contents?
Thanks in advance.
Antonio
Because the addItem() function isn't a slot, you'll need an intermediate public slot to handle the transaction. It'll be the same with the other functions you are trying to get at as well.

How can I programmatically commit data from QTableWidget, which contain some items in editing state?

How can I autocommit data from QTableWidget, that is in editing state, when I fire some command?
Assume, that there is some grid and data in it (editable thorough delegate that fires QComboBox editor). So, one starting to select option in combo, but do not finish editing, then hit some button, that executes action, that uses data from that combo, but new choise is not committed yet :\
How can I programmatically finish editing in table?
I mean some not strict 'loop all items and finish editing' way, that I consider as bad and ugly.
OOPS: worked too much, so, haven't realised, that there could be only one pending editor at time. Question is still here.
There is a protected slot named "commitData" in the tableWidget. You can inherit from tableWidget, then add your own public method (or slot) and send a signal (or simply call commitData method) from there.
There is one problem. You'll need to provide the editor object, but tableWidget gives you no way to get the pointer you need.
If you're using your own createEditor method, you can save the pointer to the editor somewhere, where your method can get it. It's a hack, but it's the only way i know.
The current editor does not seem to be accessible from outside of the view, but its content is committed when the current model index changes. So a simple way to force a commit seems to be to call
table->setCurrentIndex (QModelIndex ())
plus restoring your previous current index afterwards if the widget is not discarded yet.
This is quite an old question but it still came up quite high on Google so just in case anyone else needs the answer QTableView has a protected method
void currentChanged(const QModelIndex &current, const QModelIndex &previous)
which causes the data to be commited and QTableWidget is built on QTableView so that should still work. I found this info on the Qt Forum.

Resources