I'm writing a program using
Linux Mint 19
Python version: 3.6.6
Qt version: 5.9.5
PyQt version: 5.10.1
SIP version: 4.19.7
and I have just noticed that the standard short key for closing (CTRL+W) has stopped working.
In my file I've written the following line to connect it to the close button
self.closeBtn.setShortcut(QtGui.QKeySequence(QtGui.QKeySequence.Close))
But nothing happens if I push the buttons. If I change it to
self.closeBtn.setShortcut(QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_W))
it works as intended.
I've also tried with
self.closeBtn.setShortcut(QtGui.QKeySequence(QtGui.QKeySequence.Quit))
But CTRL+Q does nothing either. The standard keys work for other applications.
Any ideas on why that could be?
enum QKeySequence::StandardKey
This enum represent standard key bindings.
They can be used to assign platform dependent keyboard shortcuts to a QAction.
http://doc.qt.io/qt-5/qkeysequence.html#StandardKey-enum
Try it:
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class MyButton(QMainWindow):
def __init__(self,parent=None):
super().__init__(parent)
btn1 = QPushButton("Click or `Ctrl+Q`", clicked=self.close)
btn1.setShortcut(QKeySequence("Ctrl+Q"))
btn2 = QPushButton("QKeySequence.Close",
clicked=lambda: print("\n Please Press -> Ctrl+W"))
quitAct = QAction("Close", btn2, triggered=self.close)
quitAct.setShortcuts(QKeySequence.Close) # <<<=======
btn2.addAction(quitAct)
btn3 = QPushButton("Click or `Ctrl+P`", clicked=lambda: print("Hello Kajsa"))
btn3.setShortcut(QKeySequence("Ctrl+P"))
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
v_layout = QVBoxLayout(centralWidget)
v_layout.addWidget(btn1)
v_layout.addWidget(btn2)
v_layout.addWidget(btn3)
if __name__ == '__main__':
app=QApplication([])
mb = MyButton()
mb.show()
app.exec_()
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class demo_widget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
lay_content = QVBoxLayout()
self.closeBtn = QPushButton("Close")
self.lineEdit = QLineEdit()
self.closeBtn.clicked.connect(self.slt_close)
self.closeAction = QAction(self, triggered=self.slt_close)
self.closeAction.setShortcuts([QKeySequence("Ctrl+Q"), QKeySequence("Ctrl+W")])
self.closeBtn.addAction(self.closeAction)
lay_content.addWidget(self.closeBtn)
lay_content.addWidget(self.lineEdit)
self.setLayout(lay_content)
def slt_close(self):
self.lineEdit.setText("close")
if __name__ == '__main__':
app=QApplication([])
demo = demo_widget()
demo.show()
app.exec_()
Related
I am trying to use the API of my investment company(kiwoom). There is an instruction on how to use API so I was just replicating it. But the following codes keep giving me an error message that:
the PyQt5.QtCore module failed to register with the sip module
I looked it up and it seems to have to do with the compatibility of the versions of sip and pyqt5. In case you need, my SIP version is 4.19.19 and PyQt version is 5.9.2. But this is just my guess. Any help would be appreciated.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QAxContainer import *
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyStock")
self.setGeometry(300, 300, 300, 150)
self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
btn1 = QPushButton("Login", self)
btn1.move(20, 20)
btn1.clicked.connect(self.btn1_clicked)
btn2 = QPushButton("Check state", self)
btn2.move(20, 70)
btn2.clicked.connect(self.btn2_clicked)
def btn1_clicked(self):
ret = self.kiwoom.dynamicCall("CommConnect()")
def btn2_clicked(self):
if self.kiwoom.dynamicCall("GetConnectState()") == 0:
self.statusBar().showMessage("Not connected")
else:
self.statusBar().showMessage("Connected")
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = MyWindow()
myWindow.show()
app.exec_()
I have two separate files, one that creates a system tray icon and context menu, and another a window to take user input.
traywindow.py contains this:
import sys
import os
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QWidget, QLabel, QLineEdit
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import QSize
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(320, 172))
self.setWindowTitle("Set Account")
# Setup username field
self.username_label = QLabel(self)
self.username_label.setText('Username')
self.username_field = QLineEdit(self)
self.username_label.move(45, 20)
self.username_field.move(115, 23)
self.username_field.resize(150, 25)
# Setup OK button
pybutton = QPushButton('OK', self)
pybutton.clicked.connect(self.buttonClicked)
pybutton.resize(100,32)
pybutton.move(110, 128)
def buttonClicked(self):
print('Username: ' + self.username_field.text())
def displayWindow():
app = QtWidgets.QApplication(sys.argv)
preferences_window = MainWindow()
preferences_window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
displayWindow()
Which produces:
trayapp.py contains this:
import os
import sys
import traywindow
from PyQt5 import QtWidgets, QtCore, QtGui
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtWidgets.QMenu(parent)
prefs_action = menu.addAction('Preferences...')
self.setContextMenu(menu)
prefs_action.triggered.connect(self.setPrefs)
def setPrefs(self):
traywindow.displayWindow()
def main(image):
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
trayIcon = SystemTrayIcon(QtGui.QIcon(image), w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == '__main__':
icon = 'icon.png'
main(icon)
Which produces:
I want to launch the window from my context menu, so when I click on Preferences... it will open the Set Account window, and when I fill in the field and click on OK, capture that into variables/pass those along as arguments in the trayapp.py file. Currently, my attempt in the code above gives me this when I click on Preferences...:
Traceback (most recent call last):
File "/Users/Username/Downloads/trayapp.py", line 17, in setPrefs
traywindow.displayWindow()
File "/Users/Username/Downloads/traywindow.py", line 36, in displayWindow
sys.exit(app.exec_())
SystemExit: -1
[Finished in 3.0s with exit code -6]
I'm new to PyQt5 and feel like I'm missing something fundamental. From the error I think it's to do with how each file is called at the end to produce its UI, but I haven't found an answer in the docs so far.
You can only have one QApplication and in displayWindow you are creating a second QApplication, instead create a MainWindow and do not call displayWindow.
def setPrefs(self):
self.window = traywindow.MainWindow()
self.window.show()
I'm trying to make a desktop application in pyqt5 that will stay on top of all windows. I've been looking around online and they all say that the solution is to set the window flags using the setWindowFlags(Qt.WindowStaysOnTopHint) method, but this isn't working for me. Is there some other way I can do this?
I'm on Windows 10 and using Python 3.6 + pyqt5 version 5.9.2. My code is as follows:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.initUI()
self.show()
def initUI(self):
self.alertWidget = AlertWidget()
self.setCentralWidget(self.alertWidget)
class AlertWidget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
grid.setAlignment(Qt.AlignTop)
self.alertTextBox = QTextEdit()
grid.addWidget(self.alertTextBox, 0, 0)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
sys.exit(app.exec_())
Assuming the rest of your code is good, change the following line of code:
self.setWindowFlags(Qt.WindowStaysOnTopHint)
to the following line of code:
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint)
Link to an answer explaining why the code change above is required for the Qt.WindowStaysOnTop flag to work.
I copied a PyQt example from the Web into a file and opened it up in PyCharm. Below is the code:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from math import *
class Calculator(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.browser = QTextBrowser()
self.expression = QLineEdit()
self.expression.setPlaceholderText("Type an expression and press Enter.")
self.expression.selectAll()
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.expression)
self.someWidget = QWidget()
self.someWidget.setLayout(layout)
self.setCentralWidget(self.someWidget)
self.expression.setFocus()
self.expression.returnPressed.connect(self.updateUi)
self.setWindowTitle("Calculator")
def updateUi(self):
try:
text = self.expression.text()
self.browser.append("%s = %s", (text, eval(text)))
except:
self.browser.append("<font color=red>Invalid Expression</font>")
def main():
import sys
app = QApplication(sys.argv)
window = Calculator()
window.show()
sys.exit(app.exec_())
main()
The problem is that the code run well even without adding the following import statements:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from math import *
I have seen this example being used in many videos and books. If the code works good without the above statements, then why did the author of the example write the statements.
From PyQt4 to PyQt5, a lot of things moved from QtGui, QtCore to QtWidgets. To write a simple application in PyQt5, you're likely to need only QtWidgets.
My guess is that the code was originally written for PyQt4, and "adapted" to PyQt5, without removing useless imports.
The proper way to import would be import PyQt5.QtWidgets as QtWidgets ( see Should wildcard import be avoided ?).
The code then becomes:
class Calculator(QtWidgets.MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.browser = QtWidgets.QTextBrowser()
self.expression = QtWidgets.QLineEdit()
...
I'm doing some simple PySide on 3Dsmax 2015.
This is my error:
python.ExecuteFile "C:\Program Files\Autodesk\3ds Max 2015\scripts\Python\demoUniTest.py"
-- Runtime error: Line 32 <module>()
<type 'exceptions.RuntimeError'> A QApplication instance already exists.
This is my code:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
from math import *
class Form(QDialog):
def __init__(self,parent=None):
super(Form,self).__init__(parent)
self.browser = QTextBrowser()
self.lineedit = QLineEdit("Type an expression and press Enter")
self.lineedit.selectAll()
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.lineedit)
self.setLayout(layout)
self.lineedit.setFocus()
self.connect(self.lineedit, SIGNAL("returnPressed()"),self.updateUi)
self.setWindowTitle("Calculate")
def updateUi(self):
try:
text = self.lineedit.text()
self.browser.append("%s = <b>%s</b>" % (text,eval(text)))
except:
self.browser.append("<font color=red>%s is invalid</font>" %text)
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
When I use this code on Pycharm,I don't get any errors. It only appears when I use it on 3Dsmax 2015 Listener
Direct citation from the helpfile (Using PySide):
Normally one creates a PySide application object in a script using
QtGui.QApplication(). However, in 3ds Max, there is already a PySide
application running, so you get a handle for that object like this:
QtGui.QApplication.instance()
As a note this has changed somewhat in 3DS Max 2018 and PySide2. I'm just playing around with it myself right now and I was able to get it working after a bit of tinkering. Here's a link to the documentation, though be warned that there is a small typo in the code (at least at the time of writing): http://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__developer_what_s_new_in_3ds_max_python_api_what_s_new_in_the_3ds_max_2018_p_html
As mentioned in other answers you need to make your UI a child of the main 3DS Max application. The good news is that they have simplified this a bit for you with the function GetQMaxMainWindow(). Use it like this:
from PySide2 import QtWidgets, QtCore, QtGui
import MaxPlus
import os
class SampleUI(QtWidgets.QDialog):
def __init__(self, parent=MaxPlus.GetQMaxMainWindow()):
super(SampleUI, self).__init__(parent)
self.initUI()
def initUI(self):
mainLayout = QtWidgets.QHBoxLayout()
testBtn = QtWidgets.QPushButton("Test!")
mainLayout.addWidget(testBtn)
self.setLayout(mainLayout)
if __name__ == "__main__":
try:
ui.close()
except:
pass
ui = SampleUI()
ui.show()
You're creating an instance of QApplication in the line:
app = QApplication(sys.argv)
And getting that error because there's another instance of QApplication created somewhere before that (presumably somewhere in "3Dsmax 2015 Listener") and you're only allowed one.
See:
QT documentation on QApplication