Python version and bit | Qt binding | Default Used by | Install Options | ||
---|---|---|---|---|---|
Python 2.7 | 32bit | PyQt4 | Qt4 | my personal tools | https://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/ |
Python 2.7 | 64bit | PySide | Qt4 | Maya2014 64bit, Houdini v15 64bit, Nuke 10 64bit | |
Python 2.7 | 64bit | PySide2 | Qt5 | Maya2017 64bit | |
Python 3.4 | 64bit | PyQt4 | Qt4 | https://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/ | |
Python 3.4 | 64bit | PyQt5 | Qt5 | pip3 install PyQt5 | |
Python 3.5 | 64bit | PyQt4 | Qt4 | http://www.lfd.uci.edu/%7Egohlke/pythonlibs/#pyqt4 | |
Python 3.5 | 64bit | PyQt5 | Qt5 | pip3 install PyQt5 whl https://pypi.python.org/pypi/PyQt5 |
Quick notes:
Qt UI | Maya UI |
---|---|
push button (Buttons group) | button |
radio button (Buttons group) | radioButton |
check box(Buttons group) | checkBox |
combo box (containers group) | optionMenu |
line edit (input widgets group) | textField |
spin box (input widgets group) | NONE |
double spine box (input widgets group) | NONE |
dial (input widgets group) | NONE |
list widget (item widget item based) | textScrollList |
horizontal slider (input widgets) | intSlider |
label (display widgets group) | NONE |
progress bar (display widgets group) | progressBar |
vertical slider (input widgets) | intSlider |
horizontal line (input widgets) | NONE |
vertical line (input widgets) | NONE |
group box (containers group) | NONE |
tab widget (container group) | tabLayout |
main window/QWidget | window |
python -m pip install --upgrade pip
python -m pip install pyside
xcode-select --install
sudo port install python27 python_select sudo port select python python27 sudo port install py27-pyqt4 py27-qscintilla vi ~/.bash_profile
PATH="/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin:${PATH}" export PATH
Write Python Code the way that work in any code
Print Function
print "Good Job" # works print("Good Job") # works
print("Good Job") # only
print("Good Job") # upgrade old code by convert line import re old_line = 'print "Good job"' new_line = re.sub(r"(print)\s(.+)",r"\1(\2)", line) # print("Good Job") # upgrade old code by notepad++ regular replace # find : (print)\s(.+) # replace: $1\($2\), in new npp, \1(\2)
Run Python File
execfile("testScript.py")
exec(open("testScript.py").read(), globals())
Reload module
reload(myModule)
import imp;imp.reload(myModule);
user input module
a = int(raw_input())
a = int(input())
QtCore.QObject.connect(my_QButton, QtCore.SIGNAL("clicked()"), self.default_action) QtCore.QObject.connect(my_QAction, QtCore.SIGNAL("triggered()"), self.default_action) QtCore.QObject.connect(my_QCheckBox, QtCore.SIGNAL("toggled(bool)"), self.check_toggle_action)
my_QButton.clicked.connect(self.default_action) my_QAction.triggered.connect(self.default_action) my_QCheckBox.toggled[bool].connect(self.check_toggle_action)
import sys import os default_variant = 'PySide' env_api = os.environ.get('QT_API', 'pyqt') if '--pyside' in sys.argv: variant = 'PySide' elif '--pyqt4' in sys.argv: variant = 'PyQt4' elif env_api == 'pyside': variant = 'PySide' elif env_api == 'pyqt': variant = 'PyQt4' else: variant = default_variant if variant == 'PySide': from PySide import QtGui, QtCore # This will be passed on to new versions of matplotlib os.environ['QT_API'] = 'pyside' def QtLoadUI(uifile): from PySide import QtUiTools return QtUiTools.QUiLoader().load(uifile) elif variant == 'PyQt4': import sip api2_classes = [ 'QData', 'QDateTime', 'QString', 'QTextStream', 'QTime', 'QUrl', 'QVariant', ] for cl in api2_classes: sip.setapi(cl, 2) from PyQt4 import QtGui, QtCore QtCore.Signal = QtCore.pyqtSignal QtCore.QString = str os.environ['QT_API'] = 'pyqt' def QtLoadUI(uifile): from PyQt4 import uic return uic.loadUi(uifile) else: raise ImportError("Python Variant not specified") __all__ = [QtGui, QtCore, QtLoadUI, variant]
# ---- qtMode ---- qtMode = 0 # 0: PySide; 1 : PyQt, 2: PySide2, 3: PyQt5 qtModeList = ('PySide', 'PyQt4', 'PySide2', 'PyQt5') try: from PySide import QtGui, QtCore import PySide.QtGui as QtWidgets qtMode = 0 if hostMode == "maya": import shiboken except ImportError: try: from PySide2 import QtCore, QtGui, QtWidgets qtMode = 2 if hostMode == "maya": import shiboken2 as shiboken except ImportError: try: from PyQt4 import QtGui,QtCore import PyQt4.QtGui as QtWidgets import sip qtMode = 1 except ImportError: from PyQt5 import QtGui,QtCore,QtWidgets import sip qtMode = 3 print('Qt: {0}'.format(qtModeList[qtMode]))
QtNetwork = getattr(__import__(qtModeList[qtMode], fromlist=['QtNetwork']), 'QtNetwork')
QIcon QKeySequence QCursor QTextFormat QPainter QPixmap QPalette
modifiers = QtWidgets.QApplication.queryKeyboardModifiers() clickMode = 0 # basic mode if modifiers == QtCore.Qt.ControlModifier: clickMode = 1 # ctrl elif modifiers == QtCore.Qt.ShiftModifier: clickMode = 2 # shift elif modifiers == QtCore.Qt.AltModifier: clickMode = 3 # alt elif modifiers == QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier | QtCore.Qt.AltModifier: clickMode = 4 # ctrl+shift+alt elif modifiers == QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier: clickMode = 5 # ctrl+alt elif modifiers == QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier: clickMode = 6 # ctrl+shift elif modifiers == QtCore.Qt.AltModifier | QtCore.Qt.ShiftModifier: clickMode = 7 # alt+shift
Visibility control
# disable self.uiList['namePublish_input'].setDisabled(1) self.my_pushButton.setEnabled(False) # hide self.uiList[form_ui_name].hide() # toggle hidden self.uiList['server_grp'].setVisible( self.uiList['server_grp'].isHidden() )
Style Sheet code
my_pushButton.setStyleSheet("text-align: left; color: rgb(255, 128, 128)") # set button text alignment, and text color pink
QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create('Cleanlooks')) QtWidgets.QStyleFactory.keys() # Mac Only: QMacStyle as Mac # QWindowsXPStyle as WindowsXP
self.setStyleSheet("QLineEdit:disabled{background-color: gray;}") main_color = self.palette().color(QtWidgets.QPalette.Window).name() self.setStyleSheet('QTextEdit[readOnly="true"] { background-color: '+main_color+'; border: 0px }')
text_color = self.palette().color(QtGui.QPalette.Text).name()
from PySide2 import QtCore, QtGui, QtWidgets import MyToolName ui = MyToolName.main() color_info = ui.palette().color(QtGui.QPalette.Dark).name() print('color info {}'.format(color_info)) color_roles = [ QtGui.QPalette.WindowText, QtGui.QPalette.Button, QtGui.QPalette.Light, QtGui.QPalette.Midlight, QtGui.QPalette.Dark, QtGui.QPalette.Mid, QtGui.QPalette.Text, QtGui.QPalette.BrightText, QtGui.QPalette.ButtonText, QtGui.QPalette.Base, QtGui.QPalette.Window, QtGui.QPalette.Shadow, QtGui.QPalette.Highlight, QtGui.QPalette.HighlightedText, QtGui.QPalette.Link, QtGui.QPalette.LinkVisited, QtGui.QPalette.AlternateBase, QtGui.QPalette.NoRole ] print("Color roles and their corresponding colors:") for role in color_roles: color = ui.palette().color(role) print(f"{role}: {color.name()}")
sshFile="darkorange.stylesheet" with open(sshFile,"r") as fh: self.setStyleSheet(fh.read())
self.uiList['proc_list'].setStyleSheet("QListWidget::item {background-color: #656565; padding: 2px;border-style: solid;border: 1px solid black;border-radius:8px; }")
self.memoData['font_size_default'] = QtGui.QFont().pointSize() self.memoData['font_size'] = self.memoData['font_size_default'] def fontNormal_action(self): self.memoData['font_size'] = self.memoData['font_size_default'] self.setStyleSheet("QLabel,QPushButton { font-size: %dpt;}" % self.memoData['font_size']) def fontUp_action(self): self.memoData['font_size'] += 2 self.setStyleSheet("QLabel,QPushButton { font-size: %dpt;}" % self.memoData['font_size']) def fontDown_action(self): if self.memoData['font_size'] >= self.memoData['font_size_default']: self.memoData['font_size'] -= 2 self.setStyleSheet("QLabel,QPushButton { font-size: %dpt;}" % self.memoData['font_size'])
from PySide import QtGui groups = ['Disabled', 'Active', 'Inactive', 'Normal'] roles = ['Window', 'Background', 'WindowText', 'Foreground', 'Base', 'AlternateBase', 'ToolTipBase', 'ToolTipText', 'Text', 'Button', 'ButtonText', 'BrightText'] # ref: http://forums.cgsociety.org/showthread.php?t=1289854 def getPaletteInfo(palette = None): #build a dict with all the colors if palette == None: palette = QtGui.QApplication.palette() result = {} for role in roles: for group in groups: qGrp = getattr(QtGui.QPalette, group) qRl = getattr(QtGui.QPalette, role) result['%s:%s' % (role, group)] = palette.color(qGrp, qRl).rgba() return result def setPaletteFromDct(styleDict): palette = QtGui.QPalette() for role in roles: for group in groups: color = QtGui.QColor(styleDict['%s:%s' % (role, group)]) qGrp = getattr(QtGui.QPalette, group) qRl = getattr(QtGui.QPalette, role) palette.setColor(qGrp, qRl, color) QtGui.QApplication.setPalette(palette) # -- example # get maya app style maya_style = getPaletteInfo() # -- get a QMainWindow style piper = Piper.main() p_style = getPaletteInfo(piper.palette())
self.my_pushButton=my_pushButton # self is the parent, put the child as parent's property
root_pushButton.setObjectName("root_pushButton") my_app_instance.findChild(QtGui.QPushButton, QtCore.QString("root_pushButton")) # PyQt4 format
common connection
QtCore.QObject.connect(self.uiList['proj_choice'], QtCore.SIGNAL("activated(QString)"), self.proj_choice_action) QtCore.QObject.connect(self.uiList['item_tree'], QtCore.SIGNAL("itemExpanded(QTreeWidgetItem*)"), self.itemTreeExpand_action) QtCore.QObject.connect(self.uiList['item_tree'], QtCore.SIGNAL("itemClicked(QTreeWidgetItem*,int)"), self.itemTreeSelect_action) QtCore.QObject.connect(self.uiList['autoPublish_check'], QtCore.SIGNAL("toggled(bool)"), self.uiList['namePublish_input'].setDisabled)
self.uiList['proj_choice'].activated[str].connect(self.proj_choice_action) self.uiList['item_tree'].itemExpanded[QtWidgets.QTreeWidgetItem].connect(self.itemTreeExpand_action) self.uiList['item_tree'].itemClicked[QtWidgets.QTreeWidgetItem,int].connect(self.itemTreeSelect_action) self.uiList['autoPublish_check'].toggled[bool].connect(self.uiList['namePublish_input'].setDisabled) self.uiList['search_input'].textChanged.connect(self.tree_search_action) self.uiList['client_input'].returnPressed.connect(self.client_sendMsg) tree_name = 'vtx_bone_tree' self.uiList[tree_name'_search_input'].textChanged.connect( getattr(self, tree_name+"_search_action", partial(self.filter_tree,tree_name)) )
Python Qt multiple signal to single slot connection
from functools import partial self.my_tableWidget.setRowCount(len(my_List)); self.my_tableWidget.setColumnCount(2); self.my_tableWidget.setHorizontalHeaderLabels(['Current Name', 'Previous Name']); for i in range(0, len(my_List)): new_item_btn= QPushButton(self.my_tableWidget) new_item_btn.setText(my_List[i][0]) #QtCore.QObject.connect(new_item_btn, QtCore.SIGNAL("clicked()"),partial(self.buttonSelect, my_List[i][0])) # old way of connect new_item_btn.clicked.connect( partial(self.buttonSelect, my_List[i][0]) ) # new universal way of connect self.my_tableWidget.setCellWidget(i, 0, new_item_btn) def buttonSelect(self, btn_name): print btn_name
#QtCore.QObject.connect(new_item_btn, QtCore.SIGNAL("clicked()"),self.buttonSelect) # old way of connect new_item_btn.clicked.connect(self.buttonSelect) # new universal way of connect def buttonSelect(self): sender=self.sender() print str(sender.text())
Pass User Defined Function to Class Function variable holder
wip </code>
self.actionZoomIn = QtGui.QAction('Zoom In', self) self.actionZoomOut = QtGui.QAction('Zoom Out', self) key = QtCore.Qt.CTRL | QtCore.Qt.Key_Equal self.actionZoomIn.setShortcut(QtGui.QKeySequence(key)) self.actionZoomOut.setShortcut(QtGui.QKeySequence('Ctrl+-'))
self.hotkey['tab_1'] = QtWidgets.QShortcut(QtGui.QKeySequence( "Ctrl+1"), self) self.hotkey['tab_1'].activated.connect( partial(self.showTab, 0) ) def showTab(self, index): self.uiList['main_tab'].setCurrentIndex(index)
#self.hotkey['node_tree_search_clear'] = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+D"), self.uiList['node_tree'], None, None, QtCore.Qt.WidgetShortcut) self.hotkey['node_tree_search_clear'] = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+D"), self.uiList['main_tab'].widget(1), None, None, QtCore.Qt.WidgetWithChildrenShortcut) self.hotkey['node_tree_search_clear'].activated.connect(self.node_tree_search_clear_action)
import os, sys from PyQt4.QtGui import QApplication, QKeySequence from pygs import QxtGlobalShortcut SHORTCUT_SHOW = "Ctrl+Alt+S" # Ctrl maps to Command on Mac OS X SHORTCUT_EXIT = "Ctrl+Alt+F" # again, Ctrl maps to Command on Mac OS X def show_activated(): print("Shortcut Activated!") app = QApplication([]) shortcut_show = QxtGlobalShortcut() shortcut_show.setShortcut(QKeySequence(SHORTCUT_SHOW)) shortcut_show.activated.connect(show_activated) shortcut_exit = QxtGlobalShortcut() shortcut_exit.setShortcut(QKeySequence(SHORTCUT_EXIT)) shortcut_exit.activated.connect(app.exit) return_code = app.exec_() del shortcut_show del shortcut_exit sys.exit(return_code)
Event functions | ||
---|---|---|
accept() | set accepted flag to indicate the receiver want the event | |
ignore() | set accepted flag off | |
QDropEvent functions (ref: http://doc.qt.io/qt-5/qdropevent.html) | ||
acceptProposedAction() | Sets the drop action to be the proposed action | |
setDropAction() | set what action the receive to do with data | |
… | QtCore.Qt.CopyAction | Copy the data to the target |
… | QtCore.Qt.MoveAction | Move the data to the target |
… | QtCore.Qt.LinkAction | Link the source to the target |
… | QtCore.Qt.IgnoreAction | do nothing |
source() | return where the drag starts, can be a widget or zero for outside | Note, not all event type has source, so check the target object first |
mimeData() | ||
pos() | drop position | |
QDragEnterEvent functions (ref:http://doc.qt.io/qt-5/qdragenterevent.html) | ||
same as above | ||
setDropAction() | above Action option | |
accept() | accept and allow drop event |
QMimeData
Tester | Getter | Setter | MIME Types |
---|---|---|---|
hasText() | text() | setText() | text/plain |
hasHtml() | html() | setHtml() | text/html |
hasUrls() | urls() | setUrls() | text/uri-list |
hasImage() | imageData() | setImageData() | image/* |
hasColor() | colorData() | setColorData() | application/x-color |
for external drag and drop (outside widget, can be from other App or other widget | |
---|---|
my_widget.setAcceptDrops(1) | will accept drop from others |
my_widget.setDragEnabled(1) | will allow drag starts from itself to others |
for internal drag and drop | |
setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) | internally move around |
setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) | individual toggle select status |
setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) | standard explorer type selection handling |
setSelectionMode(QtWidgets.QAbstractItemView.ContiguousSelection) | forced continuous selection |
setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) | single select |
setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) | no select allowed |
# add drag and drop event for a QLineEdit, so it accept file path to set its text self.uiList['proj_filePath_input'].installEventFilter(self) # let main windows handle its event # the main window event filter function def eventFilter(self, object, event): if event.type() == QtCore.QEvent.DragEnter: data = event.mimeData() urls = data.urls() if object is self.uiList['proj_filePath_input'] and (urls and urls[0].scheme() == 'file'): event.acceptProposedAction() return 1 elif event.type() == QtCore.QEvent.Drop: data = event.mimeData() urls = data.urls() if object is self.uiList['proj_filePath_input'] and (urls and urls[0].scheme() == 'file'): filePath = unicode(urls[0].path())[1:] print(filePath) self.uiList['proj_filePath_input'].setText(filePath) return 1 return 0
class MyTree(QtWidgets.QTreeWidget): def __init__(self): QtWidgets.QTreeWidget.__init__(self) self.setDragEnabled(1) # setupUI node_list = [ 'file', 'place2dTexture', 'reverse'] [self.invisibleRootItem().addChild( QtWidgets.QTreeWidgetItem([x]) ) for x in node_list] def startDrag(self, dropActions ): # item drag activate this print('start drag') item = self.currentItem() mimeData = QtCore.QMimeData() mimeData.setText(item.text(0)) # work with Qt object, itself or other application #mimeData.setData('text/plain', unicode(item.text(0))) # not work as text like above print(item.text(0)) drag = QtGui.QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(QtCore.QPoint(12,12)) # this make it work, return the result action # if drag.start is old method, exec conflict in old code, use exec_ if drag.exec_(QtCore.Qt.CopyAction) == QtCore.Qt.CopyAction: print('Drag dropped ok.') # for demo purpose as below def dragMoveEvent(self): print('Move') currentNode = self.currentItem() if currentNode: print(currentNode.text(0)) def event(self, event): if event.type() == QtCore.QEvent.KeyPress and event.key() == QtCore.Qt.Key_Tab: print('Tab key now') return 1 return 0
cur_tree = self.uiList['main_browse'].uiList['file_tree'] cur_tree.setDragEnabled(1) cur_tree.installEventFilter(self) def eventFilter(self, object, event): cur_tree = self.uiList['main_browse'].uiList['file_tree'] if object is cur_tree and event.type()== QtCore.QEvent.ChildRemoved: # the tree drag event name #print(event.type()) currentNode = cur_tree.currentItem() if currentNode: # for multi selection case path_text = '\n'.join([unicode(node.text(0)) for node in cur_tree.selectedItems()]) # for single selection case #cur_path = unicode(currentNode.text(0)) #print(cur_path) mimeData = QtCore.QMimeData() mimeData.setText(path_text) drag = QtGui.QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(QtCore.QPoint(12,12)) if drag.exec_(QtCore.Qt.CopyAction) == QtCore.Qt.CopyAction: print('Drag dropped ok.') return 1 return 0
QDrag's method | |
---|---|
setMimeData() | store the mimedata |
setPixmap() | |
setHotSpot() | |
exec_() | start/init/exec the drag action |
qtMode = 0 # 0: PySide; 1 : PyQt, 2: PySide2, 3: PyQt5 qtModeList = ('PySide', 'PyQt4', 'PySide2', 'PyQt5') QtNetwork = getattr(__import__(qtModeList[qtMode], fromlist=['QtNetwork']), 'QtNetwork')
self.server = QtNetwork.QTcpServer() self.server_connection_list = [] # responding callback function self.server.newConnection.connect(self.server_newConnection) # format prepare self.server_SIZEOF_UINT32 = 4 # sizeof_uint16 = 2 # try start server if not self.server.listen(QtNetwork.QHostAdress('0.0.0.0'), 20180): print('Server is unable to start: %s.' % self.server.errorString()) self.server.close() # get server port if it you not use a port number # self.server.serverPort() def server_newConnection(self): # get incoming client new_client = self.server.nextPendingConnection() self.server_connection_list.append(new_client) # for msg them later new_client.disconnected.connect(new_client.deleteLater) new_client.readyRead.connect(self.server_receiveMsg) # for optional 2 way msg new_client.error.connect(self.server_error) # for optional error feedback # prepare msg msg = 'Welcome from Server' reply = QtCore.QByteArray() stream = QtCore.QDataStream(reply, QtCore.QIODevice.WriteOnly) stream.setVersion(QtCore.QDataStream.Qt_4_2) stream.writeUInt32(0) # not sure why, some writes writeUInt16() stream.writeQString(msg) # some writes writeString() stream.device().seek(0) stream.writeUInt32(reply.size() - self.server_SIZEOF_UINT32) # msg client new_client.write(reply) # optional one time client msg # new_client.disconnectFromHost() # close server by self.server.close()
# python 2,3 support unicode function try: UNICODE_EXISTS = bool(type(unicode)) except NameError: # lambda s: str(s) # this works for function but not for class check unicode = str self.socket = QtNetwork.QTcpSocket() # read note self.nextBlockSize = 0 # responding callback function self.socket.readyRead.connect(self.client_readMsg) self.socket.disconnected.connect(self.client_serverOff) # optional server off respond self.socket.error[QtNetwork.QAbstractSocket.SocketError].connect(self.client_serverError) # error[x] to client_serverError() # or error to client_serverError(e) # socket stop self.socket.abort() # sock connect self.socket.connectToHost('127.0.0.1', 20180) def client_sendMsg(self, text): request = QtCore.QByteArray() stream = QtCore.QDataStream(request, QtCore.QIODevice.WriteOnly) stream.setVersion(QtCore.QDataStream.Qt_4_2) stream.writeUInt32(0) stream.writeQString(text) # or writeString() stream.device().seek(0) stream.writeUInt32(request.size() - self.server_SIZEOF_UINT32) self.socket.write(request) self.nextBlockSize = 0 # reset ??? # responding functions def client_readMsg(self): stream = QtCore.QDataStream(self.socket) stream.setVersion(QtCore.QDataStream.Qt_4_2) if self.nextBlockSize == 0: if self.socket.bytesAvailable() < self.server_SIZEOF_UINT32: return self.nextBlockSize = stream.readUInt32() if self.socket.bytesAvailable() < self.nextBlockSize: return textFromServer = unicode(stream.readQString()) # or readString() # process textFromServer as you like def client_serverError(self): print("Error: {}".format(self.socket.errorString()))
def quickMenuAction(self, objName, title, tip, icon, menuObj): self.uiList[objName] = QtWidgets.QAction(QtGui.QIcon(icon), title, self) self.uiList[objName].setStatusTip(tip) menuObj.addAction(self.uiList[objName]) self.quickMenuAction('toggleDragMode_atn','&Enable Drag Mode','Enable Drag Mode.','', cur_menu) self.uiList['toggleDragMode_atn'].setShortcut(QtGui.QKeySequence("Ctrl+E")) self.uiList['toggleDragMode_atn'].setCheckable(1) self.uiList['toggleDragMode_atn'].setChecked(0)
self.uiList['my_btn'].setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.uiList['my_menu'] = QtWidgets.QMenu() self.uiList['select_load_atn'] = QtWidgets.QAction('Load selection', self) self.uiList['select_add_atn'] = QtWidgets.QAction('Add to selection', self) self.uiList['my_menu'].addAction(self.uiList['select_load_atn']) self.uiList['my_menu'].addAction(self.uiList['select_add_atn']) for ui_name in self.uiList.keys(): prefix = ui_name.rsplit('_', 1)[0] if ui_name.endswith('_btn'): self.uiList[ui_name].clicked.connect(getattr(self, prefix+"_action", partial(self.default_action,ui_name))) elif ui_name.endswith('_atn'): self.uiList[ui_name].triggered.connect(getattr(self, prefix+"_action", partial(self.default_action,ui_name))) self.uiList['my_btn'].customContextMenuRequested.connect(self.my_menu_call) def my_menu_call(self, point): self.uiList['vtx_assist_menu'].exec_(self.uiList['my_btn'].mapToGlobal(point)) def select_load_action(self): print('process load') def select_add_action(self): print('process add') def my_action(self): print('btn clicked')
for tree_name in ['vtx_bone_tree','vtx_vmp_tree','vtx_smp_tree', 'vtx_bsmp_tree']: self.uiList[tree_name].setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.uiList[tree_name].customContextMenuRequested.connect( getattr(self, tree_name+"_menu_call", partial(self.default_menu_call, tree_name)) ) def default_menu_call(self, ui_name, point): if ui_name in self.uiList.keys() and ui_name+'_menu' in self.uiList.keys(): self.uiList[ui_name+'_menu'].exec_(self.uiList[ui_name].mapToGlobal(point)) def vtx_bsmp_tree_menu_call(self, point): tree_name = 'vtx_bsmp_tree' cur_tree = self.uiList[tree_name] cur_node = cur_tree.currentItem() pattern = 'vtx_bsmp_tree_{0}_atn' for x in ['rename','delete','update','setBoneAll','applyAll','remove','setBone','apply','import','export']: self.uiList[pattern.format(x)].setEnabled(0) if cur_node: cur_type = str(cur_node.text(3)) if cur_type == 'bs': for x in ['rename','delete','update','setBoneAll','applyAll','remove']: self.uiList[pattern.format(x)].setEnabled(1) elif cur_type == 'attr': for x in ['rename','delete','setBone','apply','import','export']: self.uiList[pattern.format(x)].setEnabled(1) self.uiList[tree_name+'_menu'].exec_(self.uiList[tree_name].mapToGlobal(point))
def toggleTopFlag_action(self): if self.uiList['toggleTopFlag_atn'].isChecked(): self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) self.show() else: self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint) self.show() def toggleTop_action(self): self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowStaysOnTopHint) self.show()
self.show() self.raise_()
new_CustomMainWindowClass.setWindowFlags(QtCore.Qt.Widget) def setWidgetMode(self): self.setWindowFlags(QtCore.Qt.Widget) self.menuBar().hide() self.statusBar().hide() self.uiList['main_layout'].setContentsMargins(0, 0, 0, 0) def setWidgetMode(self, win_ui): win_ui.setWindowFlags(QtCore.Qt.Widget) win_ui.menuBar().hide() win_ui.statusBar().hide() win_ui.uiList['main_layout'].setContentsMargins(0, 0, 0, 0)
def closeEvent(self, event): print('Closing now')
def contextMenuEvent(self, event): menu = QtWidgets.QMenu(self) quitAction = menu.addAction("Quit") action = menu.exec_(self.mapToGlobal(event.pos())) if action == quitAction: self.close()
self.drag_position=QtGui.QCursor.pos() # need init it first after creation def mouseMoveEvent(self, event): if (event.buttons() == QtCore.Qt.LeftButton): self.move(event.globalPos().x() - self.drag_position.x(), event.globalPos().y() - self.drag_position.y()) event.accept() def mousePressEvent(self, event): if (event.button() == QtCore.Qt.LeftButton): self.drag_position = event.globalPos() - self.pos() event.accept()
using Qt Designer ui binding for Python
import PyQt4 from PyQt4 import QtGui,QtCore, uic ui_file = 'my_qt_design_ui_file.ui' # in Qt Designer, the pushButton object name is set as "my_pushButton" form, base = uic.loadUiType(ui_file) class TestWinUI(base, form): def __init__(self): super(base,self).__init__() self.setupUi(self) self.Establish_Connections() # handler functions def my_btn_fn(self): print('do something') # action listener binding def Establish_Connections(self): # old connection QtCore.QObject.connect(self.my_pushButton, QtCore.SIGNAL("clicked()"),self.my_btn_fn) # new connection format #self.my_pushButton.clicked.connect(self.my_btn_fn) def main(): global myWin myWin=TestWinUI() myWin.show() if __name__=="__main__": main()
Manually Code GUI
import PyQt4 from PyQt4 import QtGui,QtCore class TestWinUI(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) # always on top self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) #location and size self.setGeometry(300, 300, 300, 300) #title self.setWindowTitle("My Tool - v1.0") #resize self.resize(250,250) #icon self.setWindowIcon(QtGui.QIcon('icon.png')) #center self.center() #fixed size self.setFixedHeight(500) self.setMinimumHeight( 0 ) self.setMaximumHeight( 2048 ) self.setMinimumSize(128, 128) self.setMaximumSize(128, 128) # maximized self.showMaximized() # show and hide self.setVisible(True) def center(self): qr = self.frameGeometry() cp = QtGui.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def main(): global myWin myWin=TestWinUI() myWin.show()
Convert ui file to Source file
uic-qt4 my.ui -o myUI.cpp
pyuic4 my.ui -o myUI.py
compile resource like images into a py file
pyrcc4 -py3 resource.qrc -o resource_rc.py
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>images/icon.png</file> </qresource> </RCC>
import resource_rc QtGui.QPixmap(':/images/icon.png')
try: from PySide import QtGui, QtCore import PySide.QtGui as QtWidgets print("PySide Try") qtMode = 0 except ImportError: try: from PySide2 import QtCore, QtGui, QtWidgets print("PySide2 Try") qtMode = 2 except ImportError: try: from PyQt4 import QtGui,QtCore import PyQt4.QtGui as QtWidgets import sip qtMode = 1 print("PyQt4 Try") except ImportError: from PyQt5 import QtGui,QtCore,QtWidgets import sip qtMode = 3 print("PyQt5 Try") def quickMsg(msg): tmpMsg = QtWidgets.QMessageBox() # for simple msg that no need for translation tmpMsg.setWindowTitle("Info") tmpMsg.setText(msg) tmpMsg.addButton("OK",QtWidgets.QMessageBox.YesRole) tmpMsg.exec_()
def quickMsgAsk(msg, mode=0, choice=[]): # getItem, getInteger, getDouble, getText modeOpt = (QtGui.QLineEdit.Normal, QtGui.QLineEdit.NoEcho, QtGui.QLineEdit.Password, QtGui.QLineEdit.PasswordEchoOnEdit) # option: QtWidgets.QInputDialog.UseListViewForComboBoxItems if len(choice)==0: txt, ok = QtGui.QInputDialog.getText(None, "Input", msg, modeOpt[mode]) return (unicode(txt), ok) else: txt, ok = QtGui.QInputDialog.getItem(None, "Input", msg, choice, 0, 0) # current, editable return (unicode(txt), ok)
def input_dialog(title, items): input_dialog = QtGui.QInputDialog() input_dialog.setComboBoxItems(items) input_dialog.setLabelText(title) #input_dialog.setComboBoxEditable(False) input_dialog.setOption(QtGui.QInputDialog.UseListViewForComboBoxItems) done = input_dialog.exec_() user_choice = input_dialog.textValue() return user_choice,done
def font_action(self): font, ok = QtWidgets.QFontDialog.getFont() if ok: self.uiList['font_label'].setFont(font)
my_verticalLayout.setContentsMargins(0,0,0,0) # set margin of the boundingbox of layout # UI alignment my_layout.setAlignment(QtCore.Qt.AlignTop)
my_grid_layout.setSpacing(0) # 0 tight grid like maya grid # -- make grid equal size for all cells cur_layout = ui['region_grid'] # for i in range( cur_layout.rowCount() ): # cur_layout.setRowStretch( i, 1) for j in range( cur_layout.columnCount() ): cur_layout.setColumnStretch( j, 1 )
my_QSplitter = QtGui.QSplitter() my_QSplitter.setObjectName("my_QSplitter") my_QSplitter.setOrientation(QtCore.Qt.Vertical) # so the split into top to bottom panels my_QSplitter.addWidget(each_widget) # add to each split panel my_QSplitter.setSizes([200,500])
my_tab.setStyleSheet("QTabWidget::tab-bar{alignment:center;}QTabBar::tab { min-width: 100px; }")
# main_layout is top most layout main_scroll = QtWidgets.QScrollArea() main_scroll.setWidgetResizable(1) content_widget = QtWidgets.QWidget() content_layout = QtWidgets.QVBoxLayout(content_widget) main_scroll.setWidget(content_widget) test_label = QtWidgets.QLabel('Example Text') test_label.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) content_layout.addWidget(tmpLabel) main_layout.addWidget(main_scroll) # optional main_layout.setStyleSheet("QScrollArea{min-width:500 px; min-height: 400px}")
self.uiList['filter_label'].setFixedWidth(80)
QtWidgets.QApplication.focusWidget().metaObject().className()
my_widget.parentWidget()
my_widget.window()
for base in self.__class__.__bases__: print(base.__name__)
test.root_lineEdit.text()
qt_txt = QtCore.QString(u'normal text') normal_txt=str(qt_txt)
self.uiList['search_input'].textChanged.connect(self.dir_tree_search_action)
self.uiList['user_input'].setDisabled(1) # grey out look, can use style to tune better self.uiList['user_input'].setReadOnly(1) # normal look, but not editable
self.uiList['user_input'].setEchoMode(QtWidgets.QLineEdit.Password)
# make it plain text editor as pasted self.uiList['env_txt'].setAcceptRichText(0) # get back text env_text = unicode(self.uiList['env_txt'].toPlainText())
def dragEnterEvent( self, event ): data = event.mimeData() urls = data.urls() if ( urls and urls[0].scheme() == 'file' ): event.acceptProposedAction() def dragMoveEvent( self, event ): data = event.mimeData() urls = data.urls() if ( urls and urls[0].scheme() == 'file' ): event.acceptProposedAction() def dropEvent( self, event ): data = event.mimeData() urls = data.urls() if ( urls and urls[0].scheme() == 'file' ): txt = "\n".join( [unicode(url.path())[1:] for url in urls] ) # remove 1st / char self.insertPlainText( txt )
# current selected item and index self.uiList['template_choice'].currentText() self.uiList['template_choice'].currentIndex() # item count self.uiList['template_choice'].count() self.uiList['template_choice'].itemText(0) # ui response self.uiList['project_choice'].activated[str].connect(self.daily_path_update_process) self.uiList['project_choice'].activated[int].connect(self.daily_path_update_process) # make the combobox ui size auto grow to content size if possible cur_choice.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) # make the combobox dropdown size auto grow to content size, not affect combobox ui size cur_choice.view().setMinimumWidth(cur_choice.view().sizeHintForColumn(0)) # make the combobox dropdown size to a manual fix witdh cur_choice.view().setMinimumWidth(500) # make the combobox dropdown size to auto grow, but not always show to fit max content width cur_choice.view().setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
cur_table.verticalHeader().setDefaultSectionSize(20) # set default row height cur_table.horizontalHeader().setDefaultSectionSize(80) # set default column width cur_table.setColumnWidth(0,200) # set colume 0 width cur_table.setRowHeight(0,20) # set row 0 height
# get table content like (cellWidget, text) for i in range(my_tableWidget.rowCount()): print( str(my_tableWidget.item(i,1).text() ) # for cell with item print( str(my_tableWidget.cellWidget(i,0).text() ) # for cell with widget
cur_table.insertColumn(cur_table.columnCount()) cur_table.insertRow(cur_table.rowCount())
cur_table.setHorizontalHeaderLabels( ['name','address'] ) cur_table.setVerticalHeaderLabels( ['Admin','User'] )
cur_item = QtGui.QTableWidgetItem("Good One") cur_table.setItem(3, 0, cur_item)
# remove everything and clear cell size as well cur_table.clear() cur_table.setRowCount(0) cur_table.setColumnCount(0) # remove content only cur_table.clearContents()
Customize look
my_list.setAlternatingRowColors(1)
my_list.setStyleSheet("QListWidget::item {background-color: #656565; padding: 2px;border-style: solid;border: 1px solid black;border-radius:8px; }")
model = QtGui.QDirModel() # directory tree tree = QtGui.QTreeView(self) tree.setModel(model)
# clear content self.uiList['my_tree'].clear() # header related self.uiList['my_tree'].setHeaderLabels(["Name", "URL"]) self.uiList['item_tree'].setHeaderHidden(1) # set on one column for its header label cur_tree.headerItem().setText(0,cur_version) # hide column 1 self.uiList['item_tree'].setColumnHidden(1,1) # toggle column hidden def toggle_path_visible_action(self): cur_tree = self.uiList['result_tree'] for col in [1,2]: cur_tree.setColumnHidden(col,1-cur_tree.isColumnHidden(col)) # column width (not working) self.uiList['file_tree'].setColumnWidth(0,200) self.uiList['file_tree'].setColumnWidth(1,50) # auto fix width to content for request column index self.uiList['element_tree'].resizeColumnToContents(0) # prevent above auto fit cause too small column look for empty column self.uiList['element_tree'].header().setMinimumSectionSize(100) # auto column width, and no super long last column, 2 col in this example cur_tree = self.uiList['node_tree'] cur_tree.header().setStretchLastSection(0) #if qtMode < 2: if your_qt == 'qt4': cur_tree.header().setResizeMode(0, QtWidgets.QHeaderView.Stretch) # important column stretch as much as it like cur_tree.header().setResizeMode(1, QtWidgets.QHeaderView.ResizeToContents) # not important column take what it need else: cur_tree.header().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch) # qt5 cur_tree.header().setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents) # qt5 # sort self.uiList['file_tree'].setSortingEnabled(1) # force a sort cur_tree.sortByColumn(0, QtCore.Qt.AscendingOrder) # drag (ref: http://doc.qt.io/qt-4.8/qabstractitemview.html#DragDropMode-enum) self.uiList['config_tree'].setDragEnabled(1) self.uiList['config_tree'].setDragDropMode(QtGui.QAbstractItemView.InternalMove) # drag disable self.uiList['config_tree'].setDragEnabled(1) self.uiList['config_tree'].setDragDropMode(QtGui.QAbstractItemView.NoDragDrop) # connection and response self.uiList['item_tree'].itemExpanded[QtWidgets.QTreeWidgetItem].connect(self.itemTreeExpand_action) self.uiList['item_tree'].itemClicked[QtWidgets.QTreeWidgetItem,int].connect(self.contentUpdate_action) self.uiList['dir_tree'].itemDoubleClicked.connect( partial(self.tree_open_action,'dir_tree') ) self.uiList['dev_file_tree'].header().sectionDoubleClicked[int].connect(self.dev_file_tree_update_process) cur_tree.addTopLevelItem(new_node) cnt = cur_tree.topLevelItemCount() # QTreeWidgetItem # root root = cur_tree.invisibleRootItem() # node cur_node.addChild(item) selected_node.setExpanded(1) # add node_list = [ 'file', 'place2dTexture', 'reverse'] cur_tree.clear() [cur_tree.invisibleRootItem().addChild( QtWidgets.QTreeWidgetItem([x]) ) for x in node_list] # add : method 2 self.uiList['app_tree'].addTopLevelItems([ QtWidgets.QTreeWidgetItem([os.path.basename(txt),txt,'file']) for txt in txt_list]) # remove for item in cur_tree.selectedItems(): (item.parent() or root).removeChild(item) # make tree item editable for all columes new_node.setFlags(new_node.flags()|QtCore.Qt.ItemIsEditable) # change align new_node.setTextAlignment(i, QtCore.Qt.AlignRight ) # change bg to pink new_node.setBackgroundColor(0, QtGui.QColor(255,192,203, 100)) # set to brush and reset to default self.brush['fav'] = QtGui.QBrush(QtGui.QColor("#F280BF")) currentNode.setBackground(0, self.brush['fav']) currentNode.setData(0, QtCore.Qt.BackgroundRole, None)
# ref: https://stackoverflow.com/questions/2801959/making-only-one-column-of-a-qtreewidgetitem-editable # 1. disable edit on tree level self.uiList['vtx_smp_tree'].setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.uiList['vtx_smp_tree'].itemDoubleClicked.connect( partial(self.tree_edit_action,'vtx_smp_tree') ) # 2. enable edit on tree item level new_item.setFlags(new_item.flags()|QtCore.Qt.ItemIsEditable) # 3. catch double click action on tree to enable editing box on that item in that column after checking column id def tree_edit_action(self, tree_name, item, col): cur_tree = self.uiList[tree_name] if tree_name == 'vtx_smp_tree': if col == 0: cur_tree.editItem(item, col)
# expand top node for i in range(cur_tree.topLevelItemCount()): cur_tree.topLevelItem(i).setExpanded(1) # expand all cur_tree.expandAll() # expand to depth for tree view only cur_tree.expandToDepth(1) # use this code to expand to level def tree_expand(self, node, level=0): if isinstance(node, (str, unicode)): node = self.uiList[node].invisibleRootItem() # expand top node for i in range(node.childCount()): node.child(i).setExpanded(1) # sub node if level == -1: self.tree_expand(node.child(i), level) elif level > 0: level -=1 self.tree_expand(node.child(i), level)
def tree_newNode_action(self): cur_tree = self.uiList['config_tree'] node_name,ok = self.quickMsgAsk('New Setting Name') if ok and node_name != '': self.quickTree(cur_tree, [node_name, ''], 1) # all editable def tree_removeNode_action(self): self.quickTreeRemove(self.uiList['config_tree']) def quickTree(self, cur_tree, node_data, editable=0): # not per-column control on editable if not isinstance(node_data, (list, tuple)): node_data = [node_data] # 1. get current selection selected_node = cur_tree.selectedItems() if len(selected_node) > 0: selected_node = selected_node[0] else: selected_node = cur_tree.invisibleRootItem() # 2. create a new node new_node = QtWidgets.QTreeWidgetItem() for i,name in enumerate(node_data): new_node.setText(i, name) if editable == 1: new_node.setFlags(new_node.flags()|QtCore.Qt.ItemIsEditable) # 3. add it selected_node.addChild(new_node) # 4. expand it selected_node.setExpanded(1) def quickTreeRemove(self, cur_tree): root = cur_tree.invisibleRootItem() for item in cur_tree.selectedItems(): (item.parent() or root).removeChild(item) def quickTreeInfo(self, cur_tree): data = [] root = cur_tree.invisibleRootItem() child_count = root.childCount() for i in range(child_count): cur_node = root.child(i) cur_info = [] for j in range( cur_node.columnCount() ): cur_info.append( unicode(cur_node.text(j)) ) data.append(cur_info) return data def quickTreeUpdate(self, cur_tree, data): root = cur_tree.invisibleRootItem() data_len = len(data) for i in range(data_len): self.quickTree(cur_tree, data[i], 1)
self.uiList['config_tree'].itemClicked[QtWidgets.QTreeWidgetItem,int].connect(self.config_tree_select_action) def config_tree_select_action(self): currentNode = self.uiList['config_tree'].currentItem() if currentNode: self.uiList['source_txt'].setText(currentNode.text(1))
def TreeToData(self, tree, cur_node): col_count = tree.columnCount() child_count = cur_node.childCount() node_info = [ unicode( cur_node.text(i) ) for i in range(col_count) ] node_info_child = [] for i in range(child_count): node_info_child.append( self.TreeToData(tree, cur_node.child(i) ) ) return (node_info, node_info_child) def DataToTree(self, tree, cur_node, data): node_info = data[0] node_info_child = data[1] [cur_node.setText(i, node_info[i]) for i in range(len(node_info))] for sub_data in node_info_child: new_node = QtWidgets.QTreeWidgetItem() cur_node.addChild(new_node) self.DataToTree(tree, new_node, sub_data)
def tree_to_node_list(self, cur_node): node_list = [] node_list.append(cur_node) for i in range(cur_node.childCount()): node_list.extend(self.tree_to_node_list(cur_node.child(i))) return node_list
item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable)
item.setFlags(QtCore.Qt.ItemIsEnabled)
new_item.setFlags(new_item.flags() or QtCore.Qt.ItemIsUserCheckable) new_item.setCheckState(0, QtCore.Qt.Checked)
def node_check_to_text(self,cur_node, col_list): for i in col_list: if cur_node.checkState(i): cur_node.setText(i, '1') else: cur_node.setText(i, '0') for i in range(cur_node.childCount()): self.node_check_to_text(cur_node.child(i), col_list) def node_text_to_check(self, cur_node, col_list): for i in col_list: if cur_node.text(i) == '1': cur_node.setCheckState(i, QtCore.Qt.Checked) else: cur_node.setCheckState(i, QtCore.Qt.Unchecked) cur_node.setText(i,'') for i in range(cur_node.childCount()): self.node_text_to_check(cur_node.child(i), col_list)
cur_tree.setCurrentItem(cur_node) # QTreewidgetItem
cur_tree.header().hide()
self.uiList['gold_brush'] = QtGui.QBrush(QtGui.QColor(255,165,0)) # gold color self.uiList['normal_brush'] = self.uiList['vtx_bone_tree'].palette().text() # get default tree foreground color # current tree widget item col=2 cur_item.setForeground(col,self.uiList['gold_brush']) # set text to gold color cur_item.setForeground(col,self.uiList['normal_brush']) # reset to normal # note: style not working for tree widget item # cur_item.setStyleSheet("color: rgb(255, 165, 0)") # not working
QtCore.Qt.NoItemFlags | 0 | It does not have any properties set |
QtCore.Qt.ItemIsSelectable | 1 | It can be selected |
QtCore.Qt.ItemIsEditable | 2 | It can be edited |
QtCore.Qt.ItemIsDragEnabled | 4 | It can be dragged |
QtCore.Qt.ItemIsDropEnabled | 8 | It can be used as a drop target |
QtCore.Qt.ItemIsUserCheckable | 16 | It can be checked or unchecked by the user |
QtCore.Qt.ItemIsEnabled | 32 | The user can interact with the item |
QtCore.Qt.ItemIsTristate | 64 | The item is checkable with three separate states |
self.uiList['main_tab'].setStyleSheet("QTabBar::tab { height: 30px; width: 60px; }")
self.uiList['main_tab'].setStyleSheet("QTabWidget::tab-bar{alignment:center;}QTabBar::tab { min-width: 100px; }")
self.uiList['main_tab'].currentIndex() self.uiList['main_tab'].setCurrentIndex(1) self.uiList['main_tab'].count() # return total tabs
self.uiList['main_tab'].setTabPosition(QtWidgets.QTabWidget.South)
cur_tab = self.uiList['main_tab'] self.hotkey = {} for i in range( cur_tab.count() ): self.hotkey['tab_{}'.format(i)] = QtWidgets.QShortcut(QtGui.QKeySequence( "Ctrl+{}".format(i+1) ), self) self.hotkey['tab_{}'.format(i)].activated.connect(partial(cur_tab.setCurrentIndex, i))
# first, create a timer object my_timer = QtCore.QTimer() # 2nd, link alarm to a function my_timer.timeout.connect(self.time_show) # start the clock / stopwatch with a interval my_timer.start(1000) # end the clock my_timer.stop()
hostMode='' # ---- QtMode detection ---- qtMode = 0 # 0: PySide; 1 : PyQt, 2: PySide2, 3: PyQt5 qtModeList = ("PySide", "PyQt4", "PySide2", "PyQt5") try: from PySide import QtGui, QtCore import PySide.QtGui as QtWidgets print("PySide Try") qtMode = 0 if hostMode == "maya": import shiboken except ImportError: try: from PySide2 import QtCore, QtGui, QtWidgets print("PySide2 Try") qtMode = 2 if hostMode == "maya": import shiboken2 as shiboken except ImportError: try: from PyQt4 import QtGui,QtCore import PyQt4.QtGui as QtWidgets import sip qtMode = 1 print("PyQt4 Try") except ImportError: from PyQt5 import QtGui,QtCore,QtWidgets import sip qtMode = 3 print("PyQt5 Try") import nuke def frameHold_update(node_name, start_frame=1, end_frame=10, step_sec=3): node=nuke.toNode(node_name) node['first_frame'].setValue(start_frame) my_timer = QtCore.QTimer() # inner function for timer def update_process(): cur_val = node['first_frame'].value() # create a node called 'stop' to if you want to force it stop if cur_val < end_frame and not nuke.exists('stop'): node['first_frame'].setValue(cur_val+1) print('{0}/{1}'.format(cur_val+1, end_frame) ) else: my_timer.stop() print('finish') my_timer.timeout.connect(update_process) # start my_timer.start(1000*step_sec) # make your settting change below frameHold_update('FrameHold1', start_frame=2, end_frame=5, step_sec=2)
# ---- qtMode ---- qtMode = 0 # 0: PySide; 1 : PyQt, 2: PySide2, 3: PyQt5 qtModeList = ('PySide', 'PyQt4', 'PySide2', 'PyQt5') try: from PySide import QtGui, QtCore import PySide.QtGui as QtWidgets qtMode = 0 if hostMode == "maya": import shiboken except ImportError: try: from PySide2 import QtCore, QtGui, QtWidgets qtMode = 2 if hostMode == "maya": import shiboken2 as shiboken except ImportError: try: from PyQt4 import QtGui,QtCore import PyQt4.QtGui as QtWidgets import sip qtMode = 1 except ImportError: from PyQt5 import QtGui,QtCore,QtWidgets import sip qtMode = 3 print('Qt: {0}'.format(qtModeList[qtMode])) QtNetwork = getattr(__import__(qtModeList[qtMode], fromlist=['QtNetwork']), 'QtNetwork')
self.my_preview_screen = PreviewScreen() self.my_preview_screen.setMinimumSize(240, 160) def preview_grab_action(self): self.hide() QtCore.QTimer.singleShot(1 * 1000, self.preview_update_action) def preview_update_action(self): self.my_preview_screen.update() self.show() def preview_crop_action(): self.my_preview_screen.crop()
class PreviewScreen(QtWidgets.QLabel): def __init__(self): QtWidgets.QLabel.__init__(self) self.rubberBand = QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle, self) self.screen = None self.preview = None self.origin = None def mousePressEvent(self,e): self.origin = e.pos() self.rubberBand.setGeometry(QtCore.QRect(self.origin , QtCore.QSize())); self.rubberBand.show() def mouseMoveEvent(self,e): self.rubberBand.setGeometry(QtCore.QRect(self.origin , e.pos()).normalized()); def mouseReleaseEvent(self,e): pass def update(self): self.screen = QtGui.QPixmap.grabWindow(QtWidgets.QApplication.desktop().winId()) # Qt5 grab() self.preview = self.screen.scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) self.setPixmap(self.preview) def crop(self): if self.screen == None: return select_rect = self.rubberBand.geometry() preview_rect = self.preview.rect() cross_rect = select_rect.intersect(preview_rect) # now the widget can't be center as pixmap seems on left print(cross_rect.x(), cross_rect.y(), cross_rect.width(), cross_rect.height()) ratio = (self.screen.height()*1.0) / self.preview.height() para = [cross_rect.x(), cross_rect.y(), cross_rect.width(), cross_rect.height() ] self.screen = self.screen.copy(QtCore.QRect(*[x*ratio for x in para])) self.preview = self.screen.scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) self.setPixmap(self.preview) self.rubberBand.hide() def save(self, filepath, filetype): if self.screen != None: self.screen.save(filepath, filetype) def load(self, filepath): self.screen = QtGui.QPixmap(filepath) self.preview = self.screen.scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) self.setPixmap(self.preview) def clear(self): self.screen = None self.preview = None
qwidget_hwnd = qwidget_var.winId() win32gui.SetParent(child_hwnd, parent_hwnd) ctypes.windll.user32.SetParent(child_hwnd, parent_hwnd)
QDesktopServices
QLocale
local = str(QtCore.QLocale.system().name()) print(local) if local.startswith('zh') and 'CN' in self.memoData['lang']: self.setLang('CN')
QClipboard
clipboard = QtWidgets.QApplication.clipboard() clipboard.setText('Information !!')
QTime
cur_time = QtCore.QTime.currentTime() cur_date = str(QtCore.QDateTime.currentDateTime().toString('d')) cur_date_format_text = str( QtCore.QDateTime.currentDateTime().toString('yyyy.MM.dd') ) text = str(cur_time.toString("hh:mm"))
QtCore.QFile.copy(src_path, new_path) QtCore.QFile.rename(src_path, new_path)
write(const char * data, qint64 maxSize) write(const char * data) write(const QByteArray & byteArray)
Learn from others' tool