I have a QTableView that's connected to a QAbstractTableModel subclass. I'm editing the data owned by the model in response to user input in a different control (not the QTableView), and then I'm calling a method on the model that emits the dataChanged event:
void CharacterModel::characterChanged(int idx)
{
emit dataChanged(index(idx, 0), index(idx, (int)kNumColumns));
}
This works, as long as the QTableView is focused. As soon as it's not, it no longer shows the updated data. If I focus it again, it updates immediately. For example, I modified my code that's calling the above method to call setFocus() on the table view right afterwards, and everything is fine - except that my editing control loses focus every time I do anything. Not OK. I have several editing controls, including spin boxes; if I click on the spin box arrow, the FIRST update is displayed (because the table view is still focused), but then the spin box gets focused and all subsequent changes don't get displayed.
Anybody have any idea what's going on? This seems to be extremely well-defined behavior, but I can't find any reference to it anywhere.
Thanks,
Aaron
I think I've solved this. Turns out the solution is to call tableView->viewport()->repaint() after the dataChanged event fires. Calling tableView->repaint() doesn't do it.
Related
I'm using QStandardItemModel with table view.
My table allows moving rows and for user to edit a cell.
I want to catch the cell changes from user edits.
Problem is, if a user drags a row, and/or edits cells the same signals are fired. How can I grab the cell changes and ignore the row changes?
Solution is to Subclass the QStandarItemModel. Don't waste time trying to track from the GUI by item selected, clicked, pressed. Once you subclass, you're now in control of how the model (which is your data) is going to work, we can do anything.
In particular, look at ::itemData, the ::dropMimeData and ::setData functions. Between those items you know which are from internal dnd or not. You can store to var's, emit by Qt's sig/slot mechanism to GUI, or whatever your class needs.
Another useful tool is to hook into the deleget closeEditor func:
#include <QAbstractItemDelegate>
QAbstractItemDelegate * d = tv->itemDelegate();
connect(d, &QAbstractItemDelegate::closeEditor, this, &MainWindow::endEditHint);
Hope this helps anyone who might have this arise.
I have a QPlainTextEdit widget in my application which has a QSyntaxHighlighter assigned to it. Upon each content change within that text edit area, I need to get a notification (to update the global application save/changed state). However, the signal textChanged() also gets emitted each time the highlighter gets to work, which I need to filter out somehow.
I already had a look at modificationChanged(), but that doesn't seem to work either. It ignores the highlighting changes and successfully notifies me upon the first content change, but not of any subsequent changes. The documentation mentions, that I should be able to reset the internal state with setModified(false) but that method doesn't seem to exist.
Any ideas on how to filter the changes?
Do I have to switch to QTextDocument which seems to have a single contentsChanged() that is said to ignore syntax highlighting changes?
It turns out I already was on the right track...just not all the way:
I indeed need to listen to modificationChanged signals since they are emitted on content changes (which are the relevant events for my application save state handling).
I however originally did not see a way to reset the internal modification state (e.g. when my application saves its state). The reason was that setModified(bool) does not exist for the QPlainTextEdit, but I realized that each of those objects has a QTextDocument internally which does have that method. So I simply call that each time I need to reset the state to non-modified:
m_pPlainTextEdit->document()->setModified(false);
As a result, when the content is changed the next time, modificationChanged will get emitted again so that I can react to it and for example enable the "Save" icon.
BTW: The signal contentsChanged from QTextDocument is also emitted upon formatting changes, so not helpful in my scenario.
I have not tested it, it is just basically an idea.
When the user modifies the text, it is a QKeyEvent.
When the highlighter does, it is some sort of QInputMethodEvent (?)
What you could do is, check if the event is a QKeyEvent, and if it is not, block it.
You can create a filterobject class, or just define the following method in the class that contains the QTextEdit.
bool MyClass::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QKeyEvent) //The user modified the text edit
return false;
else
return true;
}
And you have to install it (for example in the constructor), if you defined it in the class that contains QTextEdit:
myTextEdit->installEventFilter(this);
Instead of hooking into modificationChanged(), and resetting the modified flag everytime, you could just hook into textChanged(). It's triggered anytime you make a change to the document, regardless if had been previously changed or not...
I have a dialog that initially has several buttons, let's call them Write, View, OK, and Cancel.
The way it should to is to have the dialog upon creation only have those three buttons and nothing more.
When the Write button is cancelled, it's supposed to create a QLineEdit object in the window above the buttons where the user can enter a new string,which when OK is then clicked will be added to an external QStringList.
When View is clicked, LineEdit should go away (if it's up) and a QListView to come up instead to view everything in that list.
The problem is, I know how to use hide() to get objects that are already in the dialog to NOT appear.
but I am having trouble figuring out how to get an object not currently on the table to appear. I'm new to using Qt so it may be something easy I'm just accidentally overlooking (in fact I hope it is).
Could anyone please offer advice? Thanks!
Just create the items normally and then set:
ui->control->setVisible(false);
after you have created the UI (after ui->setupUi(this);) possibly in the constructor (in case you use code generated by Qt Creator).
And when you need them:
ui->control->setVisible(true);
Doc for this:
http://qt-project.org/doc/qt-4.8/qwidget.html#visible-prop
when using a QListView you should also have a QListModel that provides the data to it, if you only have QStrings then a QStringListModel is premade for you to use
to add a row you can do:
int rows = model->rowCount();
model->addRow(rows,1);
QModelIndex index = model->index(rows,0);
model->setData(index, string);
I have implemented a widget which has a grid (QTableView object) and two scollbars, one horizontal and one vertical. I have implemented a function that fetches the data to be shown in the grid from a database. I want when the user pressed the arrow from the scroll bar in order to make a single step the application instntly fetch the data. On the contrary when the user scrolls with the whell or move the slider the app don’t fetch the data instantly. More specifically i want the data to be fetched when the user stops the slider for some time or releases the slider. For this reason i have used sliderReleased() signal. Moreover, i have write, as a user from this forum suggested, this code for the vertical scrolling actions.
void handleVTableScrollAction(int action)
{
switch(action)
{
case QAbstractSlider::SliderSingleStepAdd:
case QAbstractSlider::SliderSingleStepSub:
drawGrid();
requestSlot();
break;
case QAbstractSlider::SliderMove:
drawGrid();
m_Timer.start(500);
}
the timer is connected to a slot the fetches the data
connect (&m_Timer, SIGNAL(timeout()), this, SLOT (requestSlot()));
So my problem is when i wnt to make a single step (by pressing the arrow key) the app don’t responds instantly. When i press the arrow for the firtst time nothing seems to be done, but when i am pressing second time the grid follows the movement. All the other movements(wheel and slider move) work fine.
So i tried to use the valueChange() signal just like this:
connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(sliderSigleStep()));
connect(ui->verticalScrollBar, SIGNAL(sliderMoved(int)), this, SLOT(sliderMoveSlot()));
In this way the single step works fine, but the sliderMoveSlost is never called as the valueChanged singal is always emmited first.
Is there an explantion for my first issue?
Can i call a function with the condition that two signals emmited? For example call the sliderMoveSlot only if sliderMove(int) and valueChanged(int) singals emmited and call sliderSingleStep() if only valueChanged(int) is emmited.
Okay, using Qt, I'd like to know how to detect the current state of the mouse at any point in time - without a MouseEvent.
Using QCursor::pos(), you can get its position, but is there a way to determine the current state of the buttons?
Basically, I'm looking to verify the state of the mouse when a timer goes off, so it won't be related to any particular MouseEvent, and so there's no MouseEvent to query. I need to know how to query for the mouse's state - in particular the state of the buttons - without having a MouseEvent.
Oh, and I'm using Qt 3, so if such a function has been added in Qt 4 but isn't in Qt 3, it doesn't help me much (though it would still be nice to know about).
Qt::MouseButtons QApplication::mouseButtons () [static]:
Returns the current state of the buttons on the mouse. The current
state is updated syncronously as the event queue is emptied of events
that will spontaneously change the mouse state (QEvent::MousePress and
QEvent::MouseRelease events).
It should be noted this may not reflect the actual buttons held on
theinput device at the time of calling but rather the mouse buttons as
last reported in one of the above events. If no mouse buttons are
being held Qt::NoButton is returned.
Edit: hmm, I just noticed you asked about Qt3.3. This answer applies to Qt4 I'm afraid.
Is it a hard requirement that you don't use MouseEvent? Or can you use MouseEvents indirectly?
If you create a boolean variable for every button and update it with mouse pressed / released events then you could just look at the values of the relevant booleans when the timer goes off.
Update for Qt5 (5.3.2):
if (QGuiApplication::mouseButtons() == Qt::LeftButton) { ... }
I am using a QApplication, but there is no mouseButtons() function there. You will need to include <QGuiApplication>