I want to include in the argument an object name that contains a specific name from the ui file.
I have created pickers in QtDesigner and have imported them for Maya 2022.
It assigned a command to each button. But I realized I needed a huge number of commands.
It's just this scene.
from PySide2 import QtWidgets
from PySide2 import QtGui
from PySide2 import QtCore
from PySide2.QtUiTools import QUiLoader
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin
import shiboken2 as shiboken
UIFILEPATH = 'D:/MAYA/pyside_pick/ui/PicsTest5.ui'
class MainWindow(MayaQWidgetBaseMixin,QtWidgets.QMainWindow):
def __init__(self,parent=None):
super(MainWindow,self).__init__(parent)
self.UI = QUiLoader().load(UIFILEPATH)
self.setWindowTitle(self.UI.windowTitle())
self.setCentralWidget(self.UI)
#PushButton
self.UI.pushButton_sphere.clicked.connect(self.PushedCmd)
#Comand
def PushedCmd(self):
bTEXT = str(self.UI.pushButton_sphere.text())
cmds.select('pSphere1')
print(bTEXT)
def main():
window = MainWindow()
window.show()
if __name__ == '__main__':
main()
If it is given an object name like above, it certainly works.
But there are commands that need to be directed only to objects containing "pushButton_".
I tried like this
button1 = self.findChild(QtWidgets.QPushButton, 'pushButton_*')
self.button1.clicked.connect(self.testPrint)
def testPrint(self):
print(self.button1)
I meant to define button1 as a QPushButton containing 'pushButton _' and print its name when clicked.
Unfortunately, I learned that asterisks can not be used as searches.
Then, I tried like this
button1 = self.findChild(QtWidgets.QPushButton, 'pushButton_sphere')
self.button1.clicked.connect(self.testPrint)
def testPrint(self):
print(self.button1)
The result was written as (PySide2.QtWidgets.QPushButton)already deleted.
This is probably rudimentary, but being Jap I couldn't find a workable solution.
Tell me how to output the object name when I press the button, please.
Also tell me if the notation is wrong.
Related
I have a login screen dialog written using pyqt and python and it shows a dialog pup up when it runs and you can type in a certin username and password to unlock it basicly. It's just something simple I made in learning pyqt. I'm trying to take and use it somewhere else but need to know if there is a way to prevent someone from using the x button and closing it i would like to also have it stay on top of all windows so it cant be moved out of the way? Is this possible? I did some research and couldn't find anything that could help me.
Edit:
as requested here is the code:
from PyQt4 import QtGui
class Test(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
self.textUsername = QtGui.QLineEdit(self)
self.textPassword = QtGui.QLineEdit(self)
self.loginbuton = QtGui.QPushButton('Test Login', self)
self.loginbuton.clicked.connect(self.Login)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.textUsername)
layout.addWidget(self.textPassword)
layout.addWidget(self.loginbuton)
def Login(self):
if (self.textUsername.text() == 'Test' and
self.textPassword.text() == 'Password'):
self.accept()
else:
QtGui.QMessageBox.warning(
self, 'Wrong', 'Incorrect user or password')
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
if Test().exec_() == QtGui.QDialog.Accepted:
window = Window()
window.show()
sys.exit(app.exec_())
Bad news first, it is not possible to remove the close button from the window, based on the Riverbank mailing system
You can't remove/disable close button because its handled by the
window manager, Qt can't do anything there.
Good news, you can override and ignore, so that when the user sends the event, you can ignore or put a message or something.
Read this article for ignoring the QCloseEvent
Also, take a look at this question, How do I catch a pyqt closeEvent and minimize the dialog instead of exiting?
Which uses this:
class MyDialog(QtGui.QDialog):
# ...
def __init__(self, parent=None):
super(MyDialog, self).__init__(parent)
# when you want to destroy the dialog set this to True
self._want_to_close = False
def closeEvent(self, evnt):
if self._want_to_close:
super(MyDialog, self).closeEvent(evnt)
else:
evnt.ignore()
self.setWindowState(QtCore.Qt.WindowMinimized)
You can disable the window buttons in PyQt5.
The key is to combine it with "CustomizeWindowHint",
and exclude the ones you want to be disabled.
Example:
#exclude "QtCore.Qt.WindowCloseButtonHint" or any other window button
self.setWindowFlags(
QtCore.Qt.Window |
QtCore.Qt.CustomizeWindowHint |
QtCore.Qt.WindowTitleHint |
QtCore.Qt.WindowMinimizeButtonHint
)
Result with QDialog:
Reference: https://doc.qt.io/qt-5/qt.html#WindowType-enum
Tip: if you want to change flags of the current window, use window.show()
after window.setWindowFlags,
because it needs to refresh it, so it calls window.hide().
Tested with QtWidgets.QDialog on:
Windows 10 x32,
Python 3.7.9,
PyQt5 5.15.1
.
I don't know if you want to do this but you can also make your window frameless. To make window frameless you can set the window flag equal to QtCore.Qt.FramelessWindowHint
I implement a label that displays the current time in several of my PyQt5 applications. Here is a MRE:
import sys
import logging
from PyQt5 import QtWidgets, QtCore, QtGui
__log__ = logging.getLogger()
class App(QtWidgets.QApplication):
def __init__(self, sys_argv):
super(App, self).__init__(sys_argv)
self.main_view = MainView()
self.main_view.show()
class MainView(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setObjectName("MreUi")
self.resize(300, 100)
self.setWindowTitle('MreUi')
self.label = QtWidgets.QLabel()
self.setCentralWidget(self.label)
config_clock(self.label)
self.start_clocks()
def start_clocks(self):
timer = QtCore.QTimer(self)
timer.timeout.connect(self.show_time)
timer.start(1000)
def show_time(self):
current_time = QtCore.QTime.currentTime()
clock_label_time = current_time.toString('hh:mm:ss')
self.label.setText(clock_label_time)
def config_clock(label):
label.setAlignment(QtCore.Qt.AlignCenter)
font = QtGui.QFont('Arial', 24, QtGui.QFont.Bold)
label.setFont(font)
if __name__ == '__main__':
logging.basicConfig()
app = App(sys.argv)
try:
sys.exit(app.exec_())
except Exception as e:
__log__.error('%s', e)
As I implemented a similar clock in several of my PyQt apps, I thought it would be nice to implement it as a component / encapsulate it. First I thought of doing this by calling a config_clock function from any QWidget, and have that function do ~ALL of the work implementing the clock for the specified label. This would avoid having to repeat myself in multiple applications from writing/calling start_clocks and show_time instance methods of MainView. but as I started to code that ...
# from inside my QWidget:
config_clock(self.label)
# this function would live outisde the class, thus reusable by diff Qt apps:
def config_clock(label):
# start the clock
# set default font, etc for label
# instantiate QtCore.QTimer
# # but that's when I realized I've always passed self to QtCore.QTimer and that maybe encapsulating this isn't as trivial as I thought.
Should I create some kind of ClockLabel() object of my own that gets passed a QtWidget's label and can also be an instance attribute of each QtWidget that might need it? That smells kind of clunky to me. But surely there must be a way to make a 'reusable component' in PyQt, I just don't know how...
I also am not certain if the MainView(QtWidgets.QMainWindow) could rightly be referred to as the 'parent class' if I were to pass it as a parameter to a ClockLabel() class I write or a config_clock function whose signature could look like:
def config_clock(label, parent_qtwidget):
# also feels clunky and not sure if parent would be the right term
Thanks
With QtWidgets it is normal to specialize widgets by inheritance. Here is an example of how you might rearrange your code to produce a reusable widget:
class ClockLabel(QtWidgets.QLabel):
def __init__(self, parent=None):
super().__init__(parent)
self.setAlignment(QtCore.Qt.AlignCenter)
font = QtGui.QFont('Arial', 24, QtGui.QFont.Bold)
self.setFont(font)
self._timer = QtCore.QTimer(self)
self._timer.timeout.connect(self._show_time)
def start(self):
self._timer.start(1000)
def stop(self):
self._timer.stop()
def _show_time(self):
current_time = QtCore.QTime.currentTime()
clock_label_time = current_time.toString('hh:mm:ss')
self.setText(clock_label_time)
I'm trying to use the IntSlider widget in IPython.html.widgets, and I want to call a function whenever the slider value changes. Additionally, I want to pass multiple arguments into the function. I was able to use on_trait_change() to call a function but have no idea how to pass arguments:
def somefn(parameter1, parameter2):
print (parameter1, parameter2)
slider = widgets.IntSlider(min=0,max=3,step=1)
slider.on_trait_change(somefn)
I would suggest using a partial.
from IPython.display import display
import ipywidgets as widgets
def somefn(parameter1,my_arg):
print ("parameter1: {}".format(parameter1))
print ("my_arg: {}".format(my_arg))
from functools import partial
somefn_arg_0 = partial(somefn, my_arg=0)
slider = widgets.IntSlider(min=0,max=3,step=1)
slider.observe(somefn_arg_0)
display(slider)
Note I have replaced the deprecated on_trait_change with observe.
I was wondering if I can make an output interactively run a piece of code. So if for example I had a class (parts in pseudo-code):
import numpy as np
class test(object):
def __init__():
self.a = np.random.randn(10)
print ## Interactive Output: Click me to view data array##
def show():
print a
So when I create a class instance it should output some interactive link (maybe in html) or something like that and when I click it, the show() method should be called. However, I have no idea how to achieve that.
You could use the widgets shipped with the notebook (for jupyter they are an independent package).
Something like this could do what you want (Python 3):
from IPython.html import widgets
from IPython.display import display
import numpy as np
class Test(object):
def __init__(self, arraylen):
self.a = np.random.randn(arraylen)
self.button = widgets.Button(description = 'Show')
self.button.on_click(self.show)
display(self.button)
def show(self, ev = None):
display(self.a)
self.button.disabled = True
test = Test(10)
You create a button widget when you initialise the class widgets.Button(description = 'Show')
Attach an event to it button.on_click(self.show)
And display the button display(self.button)
In the show method I included a way to disable the button functionality once the array is showed self.button.disabled = True. You can comment this line if you want to show more times the array.
I've got a Qt4 application (using the PyQt bindings) which contains a QListWidget, initialized like so:
class MyList(QtGui.QListWidget):
def __init__(self):
QtGui.QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
I can add items, and this allows me to drag and drop to reorder the list. But how do I get notification when the list gets reordered by the user? I tried adding a dropMimeData(self, index, data, action) method to the class, but it never gets called.
I have an easier way. :)
You can actually access the listwidget's internal model with myList->model() - and from there there are lots of signals available.
If you only care about drag&drop, connect to layoutChanged.
If you have move buttons (which usually are implemented with remove+add) connect to rowsInserted too.
If you want to know what moved, rowsMoved might be better than layoutChanged.
I just had to deal with this and it's a pain in the ass but here's what to do:
You have to install an eventFilter on your ListWidget subclass and then watch for the ChildRemoved event. This event covers moves as well as removal, so it should work for re-arranging items with drag and drop inside a list.
I write my Qt in C++, but here's a pythonification version:
class MyList(QtGui.QListWidget):
def __init__(self):
QtGui.QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
self.installEventFilter(self)
def eventFilter(self, sender, event):
if (event.type() == QEvent.ChildRemoved):
self.on_order_changed()
return False # don't actually interrupt anything
def on_order_changed(self):
# do magic things with our new-found knowledge
If you have some other class that contains this list, you may want to move the event filter method there. Hope this helps, I know I had to fight with this for a day before figuring this out.
I found Trey Stout's answer did work however I was obviously getting events when the list order had not actually changed. I turned to Chani's answer which does work as required but with no code it took me a little work to implement in python.
I thought I would share the code snippet to help out future visitors:
class MyList(QListWidget):
def __init__(self):
QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
list_model = self.model()
list_model.layoutChanged.connect(self.on_layout_changed)
def on_layout_changed(self):
print "Layout Changed"
This is tested in PySide but see no reason it wouldn't work in PyQt.
I know this is old, but I was able to get my code to work using Trey's answer and wanted to share my python solution. This is for a QListWidget inside a QDialog, not one that is sub-classed.
class NotesDialog(QtGui.QDialog):
def __init__(self, notes_list, notes_dir):
QtGui.QDialog.__init__(self)
self.ui=Ui_NotesDialog()
# the notesList QListWidget is created here (from Qt Designer)
self.ui.setupUi(self)
# install an event filter to catch internal QListWidget drop events
self.ui.notesList.installEventFilter(self)
def eventFilter(self, sender, event):
# this is the function that processes internal drop in notesList
if event.type() == QtCore.QEvent.ChildRemoved:
self.update_views() # do something
return False # don't actually interrupt anything
Not a solution, but some ideas:
You should probably check what is returned by supportedDropActions method. It might be that you need to overwrite that method, to include Qt::MoveAction or Qt::CopyAction.
You have QListView::indexesMoved signal, but I am not sure whether it will be emitted if you're using QListWidget. It worths checking.
The QListWidget.model() approach seemed the most elegant of the proposed solutions but did not work for me in PyQt5. I don't know why, but perhaps something changed in the move to Qt5. The eventFilter approach did work, but there is another alternative that is worth considering: over-riding the QDropEvent and checking if event.source is self. See the code below which is an MVCE with all of the proposed solutions coded in for checking in PyQt5:
import sys
from PyQt5 import QtGui, QtWidgets, QtCore
class MyList(QtWidgets.QListWidget):
itemMoved = QtCore.pyqtSignal()
def __init__(self):
super(MyList, self).__init__()
self.setDragDropMode(self.InternalMove)
list_model = self.model()
# list_model.layoutChanged.connect(self.onLayoutChanged) # doesn't work
# self.installEventFilter(self) # works
self.itemMoved.connect(self.onLayoutChanged) # works
def onLayoutChanged(self):
print("Layout Changed")
def eventFilter(self, sender, event):
"""
Parameters
----------
sender : object
event : QtCore.QEvent
"""
if event.type() == QtCore.QEvent.ChildRemoved:
self.onLayoutChanged()
return False
def dropEvent(self, QDropEvent):
"""
Parameters
----------
QDropEvent : QtGui.QDropEvent
"""
mime = QDropEvent.mimeData() # type: QtCore.QMimeData
source = QDropEvent.source()
if source is self:
super(MyList, self).dropEvent(QDropEvent)
self.itemMoved.emit()
app = QtWidgets.QApplication([])
form = MyList()
for text in ("one", "two", "three"):
item = QtWidgets.QListWidgetItem(text)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setCheckState(QtCore.Qt.Checked)
form.addItem(item)
form.show()
sys.exit(app.exec_())