QDialog closing crash - qt

I have problem in ensuring the dialog is closed/released with the following Qt codes.
//Segment 1: To open a 'wait' dialog for some long-running tasks
void MainWindow::ui_showProgressDialog(QString title) {
dlgProgress = new QProgressDialog(title, tr("Cancel"), 0, 0, this);
dlgProgress->setAttribute(Qt::WA_DeleteOnClose); // line 1
dlgProgress->setModal(true);
dlgProgress->show();
connect(voidWatcher, SIGNAL(finished()),
this, SLOT(onPopulationFile()));
}
//Segment 2: Attempts to close the 'wait' dialog
void MainWindow::onPopulationFile() {
qDebug((dlgProgress == NULL) ? "true" : "false");
if (dlgProgress) //
{
qDebug("0");
dlgProgress->close(); // line 2
qDebug("1");
}
qDebug((dlgProgress == NULL) ? "true" : "false");
}
Issue: When I trigger the call 'ui_showProgressDialog' twice, the second call always crash my program. Originally, my code has no line 1 of segment 1, and from the QtCreator, it always crashes on line 2 of segment 2. Debug message shows as follow
// first call to onPopulationFile
false
0
1
false
// second call to onPopulationFile
false
0
*** CRASH ***
I read the documentation that NEVER delete objects from different threads, I'm doubt that the call 'onPopulationFile' is invoked from a non-main thread. So I added the line 1 to segment to let the program decide when the delete the object. But it seems not work. Any suggestion to the problem?
Experiment done: If I replace QProgressDialog with QDialog, the program goes without crashes, and the debug message show
// first call to onPopulationFile
false
0
1
false
// second call to onPopulationFile
false
0
1
false
So,
Why the second null test in segment 2 always fail? [Edit: I have to explicitly set the variable to NULL]
Is there any better way to close the 'wait' dialog?
I try to close/release the dialog as I want release memory as soon as possible. Do I really need to manually delete the dialog?
Platform: Qt Opensource 4.8 (x64), Windows 7 (x64), MinGW (rubenvb 4.7.2)

dlgProgress->setAttribute(Qt::WA_DeleteOnClose); deletes the widget when it is closed. As you are calling dlgProgress->close();, after this line the object it points to has been freed, and dlgProgress is now a invalid pointer.
You need to set dlgProgress to null after any call to close, or event better, use the signal Qobject::destroyed().
EDIT:
Qt::WA_DeleteOnClose specify that the object will be deleted if a close event happens. Not exactly how much time it will take. For instance if they are using QObject::deleteLater(), then the object is not deleted right away. Even if it is not the case , pieces of code like
A* a = new A;
a->dosomething();
delete a;
a->dosomething();
are undefined behavior. The second call to a->dosomething(); may crash (if you are lucky) or may not crash.

Related

PyQt signal to track when row in QTableView was moved

I am using a subclassed version of QAbstractItemModel with a QTableView and have drag-and-drop activated with a subclassed model.dropMimeData(), model.insertRows(), model.removeRows(). Now I want to show the changes after a drag-and-drop operation is finished and offer the user to undo the operation again. I therefore implemented my own dropEvent()-method for the tableView. I also set the move method to InternalMove.
I check for a confirmation of the move inside the method and then call super(widget.__class__, widget).dropEvent(event). I would expect that after this execution the row was inserted at the new position and deleted at the old position. What happens is that it inserts the row at the specified position, but it deletes row at the old position only after dropEvent() is finished. It does not matter if I call event.accept() or event.acceptProposedAction() inside the function, it always waits until dropEvent() finishes.
I am looking for a signal that tells me when a drag-and-drop operation was executed. I would expect QAbstractItemModel's rowsMoved-signal to be what I want, but it is not emitted during the dnd-operation. The signals rowsInserted and rowsRemoved are however emitted. But the rowsRemoved signal is just emitted as soon as dropEvent() finishes. Does anybody know where QTableView executes the insertion of the target row, setting of the data and the removal of the source row?
I am using python3 with PyQt5 on Windows 10.
def dropEvent_withConfirm(widget, event):
dropInd = widget.indexAt(event.pos())
if not dropInd.isValid():
event.ignore()
return
confirmGUI = ConfirmGUI("Drag Element to new position?",
"Are you sure you want to drag the element to this position?",
True)
if confirmGUI.getConfirmation():
super(widget.__class__, widget).dropEvent(event)
event.accept()
# Here I want to do something after the finished move, but here the target row was inserted, but the source row is not yet deleted
else:
event.ignore()
self.client.tblView.dropEvent = lambda e: dropEvent_withConfirm(self.client.tblView, e)
I solved it now by not relying on the super().dropEvent(), but by implementing it myself. I couldn't find a fitting signal that is emitted on finalization of the drop. Down below is my updated code:
def dropEvent_withConfirm(widget, event):
dropInd = widget.indexAt(event.pos())
if not dropInd.isValid():
event.ignore()
return
confirmGUI = ConfirmGUI("Drag Element to new position?",
"Are you sure you want to drag the element to this position?",
True)
if confirmGUI.getConfirmation():
old_row, new_row = getSrcAndDstRow()
entry = getDraggedEntry()
self.myModel.insertRows(new_row)
self.myModel.setRow(new_row, entry)
if old_row > new_row:
self.myModel.removeRows(old_row + 1)
else:
self.myModel.removeRows(old_row)
event.accept()
# Here I can now do something after the finished move
else:
event.ignore()
self.client.tblView.dropEvent = lambda e: dropEvent_withConfirm(self.client.tblView, e)

watchkit: sleep -- can the isIdleTimer be changed/disabled?

I'm looking for an equivalent to the following iOS option: UIApplication.shared.isIdleTimerDisabled = true
That is, I'd like my Watch application to stay alive longer than the quick "sleep"/idle time that gets triggered when you don't move your wrist.
Its not perfect -- the watch will still sleep with inactvity, but this extension does slow it down by tricking the watch do ignore a 'wrist-down' or 'wrist-move' motion: Add the WKExtension inside one of your #IBActions:
#IBAction func mySlidefunction(){
// ... etc ...
WKExtension.shared().isAutorotating = true;
// ... etc ...
}

"Down arrow" moves cursor to end of line - how to turn it off

In IPython Notebook / Jupyter, arrow up/down keystrokes within a cell are handled by CodeMirror (as far as I can tell). I use these actions a lot (re-bound to control-p / control-n) to move between cells; but at the end of every cell, the cursor moves to end of line first before jumping to the next cell. This is counter-intuitive and, to me, rather distracting.
Is there any way to configure CodeMirror to make this move down to be just that - a move down?
Thanks!
The moving-to-next-cell behavior is defined by IPython wrapper code, which probably checks whether the cursor is at the end of the current cell, and overrides the default CodeMirror behavior in that case. You'll have to find that handler and somehow replace it with one that checks whether the cursor is on the last line. (I don't know much about IPython, only about CodeMirror, so I can't point you at the proper way to find and override the relevant code. They might have bound the Down key, or they might have overridden the goLineDown command.)
Knowing that I wasn't alone in wanting to skip the "going to end of line" behavior when going down from the last line of a code cell, I investigated that behavior and found out that:
it's CodeMirror that goes to the end of line when you type down in the last line of a code cell (file: codemirror.js ; "methods": findPosV and moveV)
and it's IPython that decides what to do with the "down" event after it has been handled by CodeMirror (file: cell.js ; class: Cell ; method: handle_codemirror_keyevent) ; looking at the code, I saw that IPython ignores the event when not at the last character of the last line.
This essentially confirms Marijin's answer.
The primary goal being to jump to the next cell, I think there's no need to prevent CodeMirror from going to the end of that line. The point is to force IPython to handle the event anyway.
My solution was to change the code from Cell.prototype.handle_codemirror_keyevent to this:
Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
var shortcuts = this.keyboard_manager.edit_shortcuts;
var cur = editor.getCursor();
if((cur.line !== 0) && event.keyCode === 38){
// going up, but not from the first line
// don't do anything more with the event
event._ipkmIgnore = true;
}
var nLastLine = editor.lastLine();
if ((event.keyCode === 40) &&
((cur.line !== nLastLine))
) {
// going down, but not from the last line
// don't do anything more with the event
event._ipkmIgnore = true;
}
// if this is an edit_shortcuts shortcut, the global keyboard/shortcut
// manager will handle it
if (shortcuts.handles(event)) {
return true;
}
return false;
};
This code provides the desired behavior for the "down-arrow" key (almost: the cursor still goes to the end of the line, except that we don't see it, as we're already in another cell at that point), and also handles the "up-arrow" key similarly.
To modify the handle_codemirror_keyevent prototype, you have two possibilities:
You edit the cell.js file and change the code of the prototype to the code I gave above. The file is in <python>/Lib/site-packages/IPython/html/static/notebook/js or something similar depending on you distro
Much better, after the page is loaded, you change that prototype dynamically by doing this:
IPython.Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
<same code as above>
};
You can do that in your custom.js for example, or create an extension to do it (that's what I did).

Trouble binding print screen in XMonad

I'm trying to bind the print screen key in Xmonad, but it doesn't seem to work.
I have the following code in my xmonad.hs:
myKeys conf#(XConfig {XMonad.modMask = modm}) = M.fromList $
[
...
, ((0, xK_Print), spawn "scrot -q 1 $HOME/pictures/screenshots/%Y-%m-%d-%H:%M:%S.png")
...
]
However, if I press print screen nothing happens (the file isn't there). Replacing xK_Print with xK_F12 works.
Using xev, I found the keysym of print screen:
KeyPress event, serial 32, synthetic NO, window 0x1a00001,
root 0x90, subw 0x0, time 8532454, (593,435), root:(594,454),
state 0x10, keycode 218 (keysym 0xff61, Print), same_screen YES,
XKeysymToKeycode returns keycode: 107
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
KeyRelease event, serial 32, synthetic NO, window 0x1a00001,
root 0x90, subw 0x0, time 8532501, (593,435), root:(594,454),
state 0x10, keycode 218 (keysym 0xff61, Print), same_screen YES,
XKeysymToKeycode returns keycode: 107
XLookupString gives 0 bytes:
XFilterEvent returns: False
which seems to be 0xff61. But using this instead of xK_Print doesn't work as well (I checked with ghci and xK_Print is just an alias for 0xff61).
How can I bind the print screen key to something?
Of course I can use another key for the job, but it feels silly not using print screen to take a screenshot.
Try changing the $HOME to a full, hardcoded path. I think that when xmonad.hs runs, it doesn't have access to all the environment variables.
To debug this, do the following:
Map that key to something that you know works (i.e., duplicate the key binding that you used for another, working key).
If that works, then you know that Xmonad can "see" the key.
Now map that key to what you want, but send any errors to a file. E.g.,
.... spawn "scrot -q 1 $HOME/pictures/screenshots/%Y-%m-%d-%H:%M:%S.png > /home/me/errors.log 2>&1")
See what errors you get, and deal with them.

I am having trouble adding elements to a referenced vector of a map

EDIT: Forgot to mention that my programming language is C++, and my IDE is Qt Creator.
I don't understand why I am having trouble adding elements to a referenced vector of a map (i.e. sometimes it works and sometimes it fails).
For example:
class C_html4_tags {
public:
C_html4_tags();
//.......
typedef std::vector<S_html_attr_value> TYPE_attr_values;
//.....
};
//...
C_html4_tags::C_html4_tags() {
//........
map<S_browser, TYPE_attr_values> attr_supported_attr_values_map;
S_browser dummy_browser; //a fake browser key for referencing a fully Html 4.01-compliant supported attr values list
dummy_browser.name = "Dummy";
//.....
TYPE_attr_values& attr_supported_attr_values = attr_supported_attr_values_map[dummy_browser];
//......
**attr_supported_attr_values = attr_supported_attr_values_map[dummy_browser];**
//...
**attr_supported_attr_values.clear();
attr_supported_attr_values_map.clear();**
//......
**attr_supported_attr_values = attr_supported_attr_values_map[dummy_browser];**
//...
**attr_supported_attr_values.clear();
attr_supported_attr_values_map.clear();**
}
I do the bolded lines multiple times with a bunch of different attributes, with very little difference between them, without a problem until reaching this one attribute (a_tabindex_attr), in which the IDE doesn't report anything wrong when running it normally (except "The program has unexpectedly finished." However, when debugging it, it now reports:
Signal received
The inferior stopped because it received a signal from the Operating
System.
Signal name : SIGSEGV Signal meaning : Segmentation fault
And the backtrace points to the attribute I mentioned above, on the line of code which does this:
attr_supported_attr_values.clear();
Now, after adding some debugging cout lines to the code, I learned that what's happening is, for some reason, even after doing:
attr_supported_attr_values.push_back(attr_value);
the vector object which is the returned mapped value of:
attr_supported_attr_values = attr_supported_attr_values_map[dummy_browser];
is not actually being changed when I push_back an S_html_attr_value object to the referenced vector. Now, I don't why that is, since I do pretty much the exact same thing in a bunch of other attributes' code before this one, without any problem, but for some reason now, on this one, it ain't adding the object to attr_supported_attr_values (which is a reference to the returned mapped value of 'dummy_browser'). And I know this for a fact, because I outputted the size of the internal mapped value object of the map (using an iterator for the map), and it was 0 after the call to push_back(). However, what is even more odd is, I ALSO outputted attr_supported_attr_values.size() after the call to push_back(), and that was 1! Now how could that be since they're both supposed to be the same object??
Note:
The full code of what I'm talking about is below (or at least the attribute code, minus the debugging statements...):
//a_tabindex_attr:
attr_desc = "Specifies the position of an <a> element in the\n"
"tabbing order for the current document.\n"
"The tabbing order defines the order in which\n"
"elements will receive focus when navigated by\n"
"the user via the keyboard. The tabbing order\n"
"may include elements nested within other elements.\n"
"Elements that may receive focus based on tabindex\n"
"adhere to the following rules:\n\n"
"1. Those elements that support this attribute and\n"
"assign a positive value to it are navigated first.\n"
"Navigation proceeds from the element with the\n"
"lowest tabindex value to the element with the\n"
"highest value. Values need not be sequential\n"
"nor must they begin with any particular value.\n"
"Elements that have identical tabindex values\n"
"should be navigated in the order they appear\n"
"in the character stream.\n"
"2. Those elements that do not support this\n"
"attribute or support it and assign it a value\n"
"of \"0\" are navigated next. These elements are\n"
"navigated in the order they appear in the\n"
"character stream.\n"
"3. Elements that are disabled do not participate\n"
"in the tabbing order.";
attr_supported_attr_values = attr_supported_attr_values_map[dummy_browser];
attr_value_desc = "A number you specify for the tab index/order.\n"
"It must be a value between 0 and 32767.";
attr_value_content = "<i>number</i>";
attr_value = C_html4_attributes_obj.getAttrValue(attr_value_desc, attr_value_content,
attr_value_supported_browsers,
attr_value_required, attr_value_deprecated,
attr_value_notes, attr_value_tips);
attr_value.is_relative = true;
attr_supported_attr_values.push_back(attr_value);
try {
N_init_class_members::initAttr(C_html4_attributes::attr_tabindex, a_tabindex_attr, attr_desc,
attr_supported_browsers, attr_supported_attr_values_map, attr_required,
attr_deprecated, attr_notes, attr_tips);
}
catch (const char* exc) {
string exc_str = "Error! Call to N_init_class_members::initAttr() from\n"
"constructor of C_html4_tags class. That function\n"
"reported the following exception:\n\n";
exc_str += exc;
throw (exc_str.c_str()); //re-throw exception
}
a_tabindex_attr.is_standard_attr = true;
a_tabindex_attr.is_optional_attr = true;
//cleanup from attribute operations so we can begin working on the next attribute:
C_html4_attributes_obj.clear(); //wipes the slate clean for all the supported attributes' properties except content
attr_desc.clear();
attr_supported_attr_values.clear();
attr_supported_attr_values_map.clear();
attr_value_desc.clear();
attr_value_content.clear();

Resources