How to import modules ,Class Names dynamically in python PyQt5? - python

My attempt is to try to import modules and their depending classes dynamically. Here is my code. File "Sample_tabwidget_base.py" have three classes names "Contact", "Personal" and "Educational". And I need to import all those classes into my file "sample_tabwidget.py" dynamically. Googleing so many items and trying them, But lack of knowledge, I can't succeed.
File : sample_tabwidget.py
import sys
from PyQt5.QtWidgets import *
# from sample_tabwidget_base import *
import importlib
module = importlib.import_module('sample_tabwidget_base')
print(module.__doc__)
# class_ = getattr(module)
# module = __import__("sample_tabwidget_base")
# mod = getattr(module,'Contact')
# print(mod)
class MainPage(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QTabWidget Samples")
self.showMaximized()
self.subwindow = None
self.Ui()
self.show()
def Ui(self):
self.tab = QTabWidget()
self.tab.setTabsClosable(True)
self.tab.setTabShape(QTabWidget.Rounded)
self.tab.setTabPosition(QTabWidget.North)
self.tab.setMovable(True)
self.tab.setDocumentMode(True)
self.tab.setAutoFillBackground(True)
self.tab.setStyleSheet(stylesheet())
font = self.tab.font()
font.setPointSize(10)
self.tab.setFont(font)
self.right_layout = QHBoxLayout()
self.main_layout = QHBoxLayout()
self.right_frame = QFrame()
self.right_frame.setObjectName("rightframe")
self.right_frame.setStyleSheet(f"QFrame#rightframe{{background-color: lightgreen;}}")
self.right_frame.setContentsMargins(0,0,0,0)
self.right_frame.setLayout(self.right_layout)
self.right_layout.setContentsMargins(15,0,0,0)
self.right_layout.addWidget(self.tab)
self.main_layout.setContentsMargins(0,0,0,0)
self.main_layout.addWidget(self.right_frame)
self.main_layout.addStretch()
self.contacttab = Contact()
self.personaltab = Personal()
self.educationaltab = Educational()
self.setLayout(self.main_layout)
self.tab.addTab(self.contacttab, "Contacts")
self.tab.addTab(self.personaltab,"Personal")
self.tab.addTab(self.educationaltab,"Educational")
def stylesheet():
return """
QTabBar {background-color: grey;}
QTabWidget::pane {border: 0px solid yellow; top:-1px; background: grey; }
QTabBar::tab:hover{background-color:yellow;}
QTabBar::tab {background-color: grey; color : black;
border-left: 1px solid grey;border-top:1px solid grey;border-right:1px solid grey;
text-align:centre ; font-family:Trebuchet MS; padding : 10px; }
QTabBar::tab:selected {background: lightgrey;color : Black;border-bottom:5px solid red;margin-bottom: -1px;
text-align:centre ; font-family:Trebuchet MS; color:Black; padding : 10px;}
"""
if __name__ == "__main__":
app = QApplication(sys.argv)
mainwindow = MainPage()
app.setStyle("windows vista")
mainwindow.show()
sys.exit(app.exec_())
File : smaple_tabwidget_base.py
import sys
from PyQt5.QtWidgets import *
class Contact(QWidget):
def __init__(self):
super().__init__()
print("its a contact class")
self.setWindowTitle("Contact Details")
self.layout = QFormLayout()
self.layout.addRow("Name", QLineEdit())
self.layout.addRow("Address", QLineEdit())
self.setLayout(self.layout)
class Personal(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Personal Details")
self.layout = QFormLayout()
self.sex = QHBoxLayout()
self.sex.addWidget(QRadioButton("Male"))
self.sex.addWidget(QRadioButton("Female"))
self.layout.addRow(QLabel("Sex"), self.sex)
self.layout.addRow("Date of Birth", QLineEdit())
self.setLayout(self.layout)
class Educational(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Educational Details")
self.layout = QHBoxLayout()
self.layout.addWidget(QLabel("subjects"))
self.layout.addWidget(QCheckBox("Physics"))
self.layout.addWidget(QCheckBox("Maths"))
self.setLayout(self.layout)

Related

Hover Effect for Two or More Widgets at a same time?

How to make a Hover effect for Two or More QLabels at a time? For Example, In my code, I need to hover effect for Lbl1 and Lbl2 at a time. ( Either Mouse enter into a QLabel 1 or QLabel 2, both QLabels will take a Hover Effect)
from PyQt5 import QtWidgets
class Hover_Multiple(QtWidgets.QWidget):
def __init__(self):
super(). __init__()
self.setWindowTitle("Hover Effects")
self.lbl1 = QtWidgets.QLabel("Python")
self.lbl1.setFixedSize(100,50)
self.lbl1.setStyleSheet(mystyle())
self.lbl2 = QtWidgets.QLabel("PyQt5")
self.lbl2.setStyleSheet(mystyle())
self.lbl2.setFixedSize(100,50)
self.hbox = QtWidgets.QHBoxLayout()
self.hbox.addStretch()
self.hbox.addWidget(self.lbl1)
self.hbox.addWidget(self.lbl2)
self.hbox.addStretch()
self.hbox.setSpacing(0)
self.hbox.setContentsMargins(0,0,0,0)
self.setLayout(self.hbox)
def mystyle():
return"""
QLabel
{
background-color:lightgreen;
min-height : 25%; min-width : 40%;
border:0px solid;border-color:red;
text-align:centre ;font-size :10pt; font-family:Trebuchet MS; color:Black; padding : 2px;
}
QLabel::hover
{
background-color: red;
color :white;
}
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainwindow = Hover_Multiple()
mainwindow.show()
sys.exit(app.exec_())
A possible solution is to use a qproperty that serves as a flag to change the painting, and that qproperty must be changed in the widgets when some widget is triggered by the QEvent::HoverEnter and QEvent::HoverLeave events and that can be done using an eventfilter.
from PyQt5 import QtCore, QtWidgets
class HoverHelper(QtCore.QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._widgets = []
#property
def widgets(self):
return self._widgets
def add_widget(self, widget):
if not isinstance(widget, QtWidgets.QWidget):
raise TypeError(f"{widget} must be QWidget object")
widget.installEventFilter(self)
widget.setAttribute(QtCore.Qt.WA_Hover)
self.widgets.append(widget)
def eventFilter(self, obj, event):
if obj in self.widgets:
if event.type() == QtCore.QEvent.HoverEnter:
self.change_property(True)
elif event.type() == QtCore.QEvent.HoverLeave:
self.change_property(False)
return super().eventFilter(obj, event)
def change_property(self, hovered):
for widget in self.widgets:
widget.setProperty("hovered", hovered)
widget.style().polish(widget)
class Hover_Multiple(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Hover Effects")
self.setStyleSheet(style_sheet())
self.lbl1 = QtWidgets.QLabel("Python")
self.lbl1.setFixedSize(100, 50)
self.lbl2 = QtWidgets.QLabel("PyQt5")
self.lbl2.setFixedSize(100, 50)
lay = QtWidgets.QHBoxLayout(self)
lay.addStretch()
lay.addWidget(self.lbl1)
lay.addWidget(self.lbl2)
lay.addStretch()
lay.setSpacing(0)
lay.setContentsMargins(0, 0, 0, 0)
helper = HoverHelper(self)
helper.add_widget(self.lbl1)
helper.add_widget(self.lbl2)
def style_sheet():
return """
QLabel{
background-color: lightgreen;
min-height: 25%;
min-width: 40%;
border: 0px solid;
border-color: red;
text-align: center;
font-size: 10pt;
font-family: Trebuchet MS;
color: black;
padding: 2px;
}
QLabel[hovered="true"]{
background-color: red;
color: white;
}
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainwindow = Hover_Multiple()
mainwindow.show()
sys.exit(app.exec_())

How to add styles to widgets inside custom Qwidget

I am having a Custom widget that contains a QLabel and a custom label(MessageLabel). I would like to know how I can add css styles to the QLabel inside the custom widget.
Here is my code.
from PyQt5 import QtWidgets, QtCore
import sys
_style = """
#MessageLabel{
background-color: rgba(196, 195, 192, 100);
color: white;
padding: 10px;
border-radius: 5px 5px 30px 5px;
selection-color: black;
selection-background-color: white;
}
#MessageDisplayWidget #InfoLabel{
color: red;
background-color: blue;
}
"""
class MessageLabel(QtWidgets.QLabel):
def __init__(self, *args, **kwargs):
super(MessageLabel, self).__init__(*args, **kwargs)
self.setObjectName("MessageLabel")
font = self.font()
font.setPointSize(12)
self.setFont(font)
self.setMinimumWidth(100)
self.setText("Hello World")
class MessageDisplayWidget(QtWidgets.QWidget):
def __init__(self):
super(MessageDisplayWidget, self).__init__()
self.message_box_frame = QtWidgets.QFrame()
self.vBoxLayout = QtWidgets.QVBoxLayout(self.message_box_frame)
self.vBoxLayout.setSpacing(0)
self.setLayout(self.vBoxLayout)
self.message_lbl_layout = QtWidgets.QVBoxLayout()
self.more_options_layout = QtWidgets.QHBoxLayout()
self.more_options_layout.setContentsMargins(0, 0, 0, 0)
self.vBoxLayout.addLayout(self.message_lbl_layout, 1)
self.vBoxLayout.addLayout(self.more_options_layout, 0)
self.message_text = MessageLabel() # this is a custom label
self.info_label = QtWidgets.QLabel("time") # this is the label I want to change
self.info_label.setObjectName("InfoLabel")
self.info_label.setFixedHeight(30)
self.message_lbl_layout.addWidget(self.message_text)
self.more_options_layout.addWidget(self.info_label)
self.more_options_layout.setStretch(0, 1)
self.more_options_layout.setAlignment(self.info_label, QtCore.Qt.AlignRight)
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = MessageDisplayWidget()
win.setStyleSheet(_style)
win.show()
sys.exit(app.exec_())
"""
QVboxlayout
|
- QVboxLayout(Message), QVboxLayout(MoreOptions)
| |
MessageLabel InfoLabel
"""
As shown in the above image I would like to add css style to time label

How to bring QLineEdit() & QPushButton to centre of Login window?

I am creating a LoginWindow and am using QLineEdit in order to make a place for my users to enter their details. Right now, I'm focused on creating the GUI. As shown in the picture, I am not sure why the layout looks like that, considering how I have setAlignment to AlignCenter. This also goes for QPushButton. Is there a class I am not aware to fix this formatting issue?
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QPushButton, QLineEdit, QVBoxLayout
import time #For time sleep
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("MidiScribe - Login Window")
self.setFixedSize(800,800)
self.setStyleSheet("""background-color: crimson;
border-color: maroon;
border: 2.5px outset rgb(128, 128, 128);
border-radius: 3px;""")
container = QWidget()
self.setCentralWidget(container)
mainLayout = QVBoxLayout(container)
self.username = QLineEdit()
self.username.setFixedWidth(300)
self.username.setStyleSheet("""background-color: white;""")
mainLayout.addWidget(self.username)
self.username.setAlignment(QtCore.Qt.AlignCenter)
self.setLayout(mainLayout)
self.password = QLineEdit()
self.password.setFixedWidth(300)
self.password.setStyleSheet("""background-color: white""")
mainLayout.addWidget(self.password)
self.password.setAlignment(QtCore.Qt.AlignCenter)
self.setLayout(mainLayout)
self.loginbutton = QPushButton("Login")
self.loginbutton.setFixedSize(50,50)
self.loginbutton.setStyleSheet("QPushButton { background-color: lightcoral }"
"QPushButton:Hover { background-color: lightpink }"
"QPushButton:pressed { background-color: indianred }" )
mainLayout.addWidget(self.loginbutton)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
There are many solutions for this case, but among them is to use a container that has the minimum size to show all the widgets and that is established through a QGridLayout:
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("MidiScribe - Login Window")
self.setFixedSize(800, 800)
self.setStyleSheet(
"""background-color: crimson;
border-color: maroon;
border: 2.5px outset rgb(128, 128, 128);
border-radius: 3px;"""
)
self.username = QLineEdit(alignment=QtCore.Qt.AlignCenter)
self.username.setFixedWidth(300)
self.username.setStyleSheet("""background-color: white;""")
self.password = QLineEdit(alignment=QtCore.Qt.AlignCenter)
self.password.setFixedWidth(300)
self.password.setStyleSheet("""background-color: white""")
self.loginbutton = QPushButton("Login")
self.loginbutton.setFixedSize(50, 50)
self.loginbutton.setStyleSheet(
"QPushButton { background-color: lightcoral }"
"QPushButton:Hover { background-color: lightpink }"
"QPushButton:pressed { background-color: indianred }"
)
container = QWidget(objectName="container")
container.setStyleSheet("QWidget#container{border: none}")
container.setContentsMargins(0, 0, 0, 0)
lay = QVBoxLayout(container)
lay.addWidget(self.username, alignment=QtCore.Qt.AlignCenter)
lay.addWidget(self.password, alignment=QtCore.Qt.AlignCenter)
lay.addWidget(self.loginbutton, alignment=QtCore.Qt.AlignCenter)
container.setFixedSize(container.sizeHint())
central_widget = QWidget()
self.setCentralWidget(central_widget)
grid_layout = QGridLayout(central_widget)
grid_layout.addWidget(container, 1, 1)
Just do alignment for mainLayout:
mainLayout.addWidget(self.loginbutton, alignment=QtCore.Qt.AlignCenter)
mainLayout.setAlignment(QtCore.Qt.AlignCenter)

pyqt4 widget appear outside the layout

I want the effect in the picture. The qlabel is in the layout, and the font is centered. Below is the code I wrote, which is different from what I want. First, qlabel is outside the layout, and second, the font is not centered.
import sys
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QLabel, QApplication, QWidget, QVBoxLayout, QStyleOption, QPainter, QStyle
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.setGeometry(100, 100, 500, 500)
vbox = QVBoxLayout()
self.setLayout(vbox)
a = QLabel('aaa')
b = QLabel('bbb')
vbox.addWidget(a)
vbox.addWidget(a, alignment=Qt.AlignHCenter | Qt.AlignTop)
vbox.addWidget(b, alignment=Qt.AlignHCenter | Qt.AlignBottom)
self.setStyleSheet("""
Example{
border-width: 1px;
border-style: solid;
border-color: red;
min-width:500px;
max-width:500px;
min-height:500px;
max-height:500px;
padding:1px 1px 1px 1px;
margin-bottom:30px;
}
QLabel{
min-width:500px;
max-width:500px;
min-height:50px;
max-height:50px;
margin:0px;
padding:0px;
background-color:#cdcdcd;
text-align: center center;
}
""")
self.show()
def paintEvent(self, event):
super(Example, self).paintEvent(event)
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The logic of the layouts is to handle the geometry of the elements but you are also handling the geometry with the stylesheet, causing the problem you observe. On the other hand, the QLabel does not have the text-align property but you have to use qproperty-alignment: AlignCenter;.
To avoid this it is better to avoid managing the geometry with stylesheet but with the methods of the class, considering the solution is:
import sys
from PyQt4.QtCore import Qt
from PyQt4.QtGui import (
QLabel,
QApplication,
QWidget,
QVBoxLayout,
QStyleOption,
QPainter,
QStyle,
)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.setGeometry(100, 100, 500, 500)
self.label_a = QLabel("aaa")
self.label_b = QLabel("bbb")
self.label_a.setFixedHeight(50)
self.label_b.setFixedHeight(50)
vbox = QVBoxLayout(self)
vbox.setContentsMargins(1, 1, 1, 1)
vbox.addWidget(self.label_a)
vbox.addWidget(QWidget(), stretch=1)
vbox.addWidget(self.label_b)
self.setFixedSize(500, 500)
self.setStyleSheet(
"""
Example{
border-width: 1px;
border-style: solid;
border-color: red;
padding:1px 1px 1px 1px;
}
QLabel{
margin:0px;
padding:0px;
background-color:#cdcdcd;
qproperty-alignment: AlignCenter;
}
"""
)
def paintEvent(self, event):
super(Example, self).paintEvent(event)
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

How to draw border around QListWidgetItem

The code below creates a QListWidget with QListWidgetItem assigned a thumb image.
I would appreciate if you show how to make a color border around of the QListWidgetItem
Here is the Photoshoped image showing a concept:
from PyQt4 import QtGui, QtCore
import sys, os
class MyClassItem(QtGui.QListWidgetItem):
def __init__(self, parent=None):
super(QtGui.QListWidgetItem, self).__init__(parent)
class ThumbListWidget(QtGui.QListWidget):
def __init__(self, type, parent=None):
super(ThumbListWidget, self).__init__(parent)
self.setIconSize(QtCore.QSize(64, 64))
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow,self).__init__()
self.listItems={}
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.listWidgetA = ThumbListWidget(self)
for i in range(7):
listItemAInstance=MyClassItem()
name='A'+'%04d'%i
listItemAInstance.setText(name)
listItemAInstance.setBackgroundColor(QtCore.Qt.darkGray)
if i%2: listItemAInstance.setBackgroundColor(QtCore.Qt.gray)
icon=self.getIcon(name)
listItemAInstance.setIcon( icon )
self.listWidgetA.addItem(listItemAInstance)
listItemBInstance=MyClassItem()
name='B'+'%04d'%i
listItemBInstance.setText(name)
icon=self.getIcon(name)
listItemBInstance.setIcon( icon )
myBoxLayout.addWidget(self.listWidgetA)
def getIcon(self, name):
thumbpath=os.path.expanduser("~")+'/thumbs/' +name+'/'+name+'.jpg'
if not thumbpath: return
if not os.path.exists(os.path.dirname(thumbpath)):
os.makedirs(os.path.dirname(thumbpath))
img = QtGui.QImage(64, 64, QtGui.QImage.Format_RGB32)
img.fill(QtGui.QColor(96,96,96))
painter = QtGui.QPainter(img)
font = painter.font()
font.setBold(True)
font.setPointSize(18)
painter.setPen(QtGui.QColor('black'))
painter.setFont(font)
painter.drawText(img.rect(), QtCore.Qt.AlignCenter, name)
painter.end()
img.save(thumbpath, 'JPG')
icon = QtGui.QIcon( thumbpath )
pixmap = icon.pixmap(64, 64)
icon = QtGui.QIcon(pixmap)
return icon
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
dialog_1.resize(720,480)
sys.exit(app.exec_())
Every class that derives from QWidget supports CSS styling. What you could do is something such as:
lwi = QListWidget()
lwi.setStyleSheet("QListWidget::item { border: 0px solid red }")
For more info, see http://qt-project.org/doc/qt-4.8/qwidget.html#styleSheet-prop
You can also style your entire application, but apply a certain part of styling only to QListWidgetItem by putting it as a prefix.
C++ example I found:
app.setStyleSheet("QListWidget { background: red; } QListWidget::item { background: yellow; } QListWidget::item:selected { background: blue; }");

Categories