Run command when X button is clicked - button

Currently I working with maya and I want to execute a command when I close a window.
So far I haven't found any solution to run a command when the windows X button is clicked except to create a custom button and use deleteUI..
Is there a flag or something to so it easier?

You could use a scriptJob. It will run a process in the background based on your conditions.
from pymel.core import *
win = window()
win.show()
def uiDel(ui):
print ui, "deleted"
scriptJob(uid=[win.name(), "uiDel(win.name())"])
Now when the ui is closed, or the X button is pressed, it will print "window1 deleted".

Related

Streamlit button works only once

I want to create a simple streamlit application, that when you press the button, it increments x and shows the new value of x.
However, it works only for the 1st time "x only shows the value 2 and doesn't increment"
import streamlit as st
x = 1
if st.button("Increment x"):
x=x+1
st.text(x)
Streamlit re-runs the webpage script every time you make a change/interaction. So each time you click the button it resets x=1, then adds 1 to x.
Your button is working correctly, the issue is in the way streamlit handles events. You could try using st.cache to work around this, but I've never tried to replicate what you're aiming for.
https://gist.github.com/tvst/036da038ab3e999a64497f42de966a92
Hey, this package worked wonders for me.
Download the code into the same folder you're working on and boom:
import SessionState
ss = SessionState.get(x=1)
if st.button("Increment x"):
ss.x = ss.x + 1
st.text(ss.x)
Streamlit's session state makes it possible to increment a value with the click of a button.
import streamlit as st
btn = st.button("Press Me")
if btn:
if 'x' in st.session_state.keys():
st.session_state['x']=st.session_state['x']+1
else:
st.session_state['x']=1
if 'x' in st.session_state.keys():
st.write(st.session_state['x'])
X will increment by 1 for each button click.

Moving the cursor in a PyQt5 text edit doesn't work

I'm contributing to Frescboaldi, a PyQt5 application and experience problems interacting with the core text edit component.
It seems whatever I try I can't get either of setPosition or movePosition to work.
The code
cursor.insertText("Hello")
cursor.setPosition(cursor.position() - 5)
properly inserts the text Hello in the document but leaves the cursor at the end of the inserted text (instead of moving it to the left by 5 characters). The first line proves that cursor, textedit and document are set up properly. trying movePosition doesn't have any effect either.
The actual goal is to insert some text, have it selected and the cursor at the end of the selection as can be seen in https://github.com/wbsoft/frescobaldi/blob/master/frescobaldi_app/cursortools.py#L179
Am I doing anything wrong here? Could this be a bug in Qt/PyQt? Or could this be an issue in PyQt5?
[Edit:] I've now confirmed with a minimal app example that the problem can't be in the larger construction of the application. In the following mini app neither setPosition nor movePosition has any effect - while insertText works well:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QTextEdit
def main():
app = QApplication(sys.argv)
w = QTextEdit()
w.setWindowTitle('Manipulate cursor')
cursor = w.textCursor()
cursor.insertText("Hello World")
# neither of the following commands have any effect
cursor.setPosition(cursor.position() - 5)
cursor.movePosition(cursor.movePosition(cursor.Left, cursor.KeepAnchor, 3))
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You are working on a local copy of the text cursor returned by w.textCursor. You should call w.setTextCursor(cursor) at the end to change the visible cursor.
A second problem is that you use the output of movePosition to call movePosition again, which is not allowed:
cursor.movePosition(cursor.movePosition(cursor.Left, cursor.KeepAnchor, 3))
should be
cursor.movePosition(cursor.Left, cursor.KeepAnchor, 3)
Note that I tested it in Qt (not PyQt), but that should not make any difference, which successfully selected lo of Hello world.

How to test drag and drop behavior in PyQt?

I want to unittest drag and drop for our widgets. At the moment, I instantiate a QDragEnterEvent, but this is discouraged with a big warning on the Qt documentation, because it relies on the Qt library internal state. In fact, I get segfaults that appear to be due to a violation of this Warning.
Given this premise, how can one test drag and drop behavior?
If using Unix we can use QTest, however to get a cross-platform solution, we can implement a solution where we circumvent Qt.
Using QTest
Although the Qt documentation for drag and drop says that it will not block the main event loop, a closer look at QDrag.exec will reveal that this is not true for Windows.
The call to QTest.mousePress causes the test to block until the mouse is physically moved by the user.
I got around this in Linux by using a timer to schedule the mouse move and release:
def testDragAndDrop(self):
QtCore.QTimer.singleShot(100, self.dropIt)
QtTest.QTest.mousePress(dragFromWidget, QtCore.Qt.LeftButton)
# check for desired behaviour after drop
assert something
def dropIt(self):
QtTest.QTest.mouseMove(dropToWidget)
QtTest.QTest.mouseRelease(dropToWidget, QtCore.Qt.LeftButton, delay=15)
For this solution, it is necessary to include a delay in the mouseRelease call, and to have called show on your widget.
Note that I have verified this works using pyqt4 and Python 2.7 on Fedora 20
Cross-Platform
You can use the mouse manipulation methods from the PyUserInput package. Put the mouse interaction in separate thread to avoid the locking up of the Qt main event loop. We can do this since we are not using Qt at all in our mouse control. Make sure that you have called show on the widgets you are dragging to/from.
from __future__ import division
import sys, time, threading
import numpy as np
from PyQt4 import QtGui, QtCore, QtTest
from pymouse import PyMouse
...
def mouseDrag(source, dest, rate=1000):
"""Simulate a mouse visible mouse drag from source to dest, rate is pixels/second"""
mouse = PyMouse()
mouse.press(*source)
# smooth move from source to dest
npoints = int(np.sqrt((dest[0]-source[0])**2 + (dest[1]-source[1])**2 ) / (rate/1000))
for i in range(npoints):
x = int(source[0] + ((dest[0]-source[0])/npoints)*i)
y = int(source[1] + ((dest[1]-source[1])/npoints)*i)
mouse.move(x,y)
time.sleep(0.001)
mouse.release(*dest)
def center(widget):
midpoint = QtCore.QPoint(widget.width()/2, widget.height()/2)
return widget.mapToGlobal(midpoint)
def testDragAndDrop(self):
# grab the center of the widgets
fromPos = center(dragFromWidget)
toPos = center(dropToWidget)
dragThread = threading.Thread(target=mouseDrag, args=((fromPos.x(),fromPos.y()), (toPos.x(), toPos.y())))
dragThread.start()
# cannot join, use non-blocking wait
while dragThread.is_alive():
QtTest.QTest.qWait(1000)
# check that the drop had the desired effect
assert dropToWidget.hasItemCount() > 0
Note I have tested this using PyQt4 and Python 2.7 on Fedora and Windows 7
Haven't tried, but if your drag & drop process is Qt internal (meaning, you're dragging from and to a Qt widget), QTest might help.
Basically by doing something along the lines:
QTest.mousePress(drag_widget, Qt.LeftButton) # simulate mouse press on whatever you want to drag
QTest.mouseMove(drop_widget) # move the mouse to the target - maybe this can be skipped
QTest.mouseRelease(drop_widget, Qt.LeftButton) # simulate mouse release where you want to drop
All functions may be supplied with further positional information (e.g. to click a list item within a widget) and with optional delays to emulate a human user.
Not a copy-pasteable answer, but maybe it serves as a starter...

Displaying 2nd Window Issue

I am dealing with 2 windows . One is created by Qt Designer and i import it
on test.py program . what i did i make a Widget on the test program and
than add a button to it and on click event I try to popup the other
window(gui1.py) created by Qt Designer but it never pop ups and when i use
break and do line by line debugging it shows me this message after running
this command "myapp2 = MyForm()" on line number 35 test.py .
QCoreApplication::exec: The event loop is already running
and once i pressed enter on the terminal it pop up the other window .
I am confuse where i am wrong .
Thanks
test.py
gui1.py
The reason the other window doesn't appear, is because you are not keeping a reference to it, and so it gets garbage-collected immediately after it is shown.
To fix the problem, you could either store the window instance it as an attribute, or give it a parent:
def local_manag(self):
print "pressed"
# store it as an attribute
self.myapp2 = MyForm()
self.myapp2.show()
# or give it a parent
# myapp2 = MyForm(self)
# myapp2.show()

Adding detailed text in QMessageBox makes close (X) button disabled

I noticed an interesting thing - if I add a detailed text to QMessageBox (which adds "Show Details..." button) then executing it will show the system frame's close (X) button disabled and hence marking this window as non-closable (right click on frame -> Close disabled).
Here is some sample code:
QMessageBox box(QMessageBox::Critical, title, text, QMessageBox::Ok);
box.setDetailedText(detailedText); // comment this line to get close button enabled
box.exec();
I didn't even find a way to manually do this in Qt. Any ideas?
Thanks
I was having the same problem with Python 2.7 and PySide.
In this example, the red close button works as expected:
from PySide import QtGui, QtCore
import sys
app = QtGui.QApplication(sys.argv)
message_box = QtGui.QMessageBox()
message_box.setWindowTitle("Close Test")
message_box.setText("Testing whether or not the red X is enabled.")
ret = message_box.exec_()
Adding detailed text disables the close button:
from PySide import QtGui, QtCore
import sys
app = QtGui.QApplication(sys.argv)
message_box = QtGui.QMessageBox()
message_box.setWindowTitle("Close Test")
message_box.setText("Testing whether or not the red X is enabled.")
message_box.setDetailedText("These details disable the close button for some reason.")
ret = message_box.exec_()
The answer marked as the solution does not solve this problem. As you can see in this example, the close button remains disabled:
from PySide import QtGui, QtCore
import sys
app = QtGui.QApplication(sys.argv)
message_box = QtGui.QMessageBox()
message_box.setWindowTitle("Close Test")
message_box.setText("Testing whether or not the red X is enabled.")
message_box.setDetailedText("These details disable the close button for some reason.")
message_box.setWindowFlags(message_box.windowFlags() & ~QtCore.Qt.WindowCloseButtonHint)
ret = message_box.exec_()
The answer is to set the standard buttons and ALSO set the escape button:
from PySide import QtGui, QtCore
import sys
app = QtGui.QApplication(sys.argv)
message_box = QtGui.QMessageBox()
message_box.setWindowTitle("Close Test")
message_box.setText("Testing whether or not the red X is enabled.")
message_box.setDetailedText("These details disable the close button for some reason.")
message_box.setStandardButtons(QtGui.QMessageBox.Ok)
message_box.setDefaultButton(QtGui.QMessageBox.Ok)
message_box.setEscapeButton(QtGui.QMessageBox.Ok)
ret = message_box.exec_()
This restores the desired close button behavior.
I came across this recently on Qt 4.8 Linux. I found that whether or not the X was disabled depended on the ButtonRole I used on the call to QMessageBox::addButton(). The X was disabled when all roles were ActionRole - which is really supposed to be for buttons that affect the dialog, but do not accept or reject it. What the buttons did in my case is more accurately described as AcceptRole or RejectRole. When I changed the roles to have one RejectRole and the rest AcceptRole, the X started working. It looks as though QMessageBox was reluctant to accept a close when none of the buttons had roles that mapped to close.
You need to unset the Qt::WindowCloseButtonHint widget flag. Like this:
QMessageBox messageBox;
messageBox.setWindowFlags(messageBox.windowFlags() & ~Qt::WindowCloseButtonHint);
You may unset this flag Qt::WindowSystemMenuHint either.
Adds a window system menu, and possibly a close button (for example on
Mac). If you need to hide or show a close button, it is more portable
to use WindowCloseButtonHint.
http://qt-project.org/doc/qt-4.8/qt.html#WindowType-enum

Resources