I display a window where more than 30 Checkbox(on the basic of results in database), This code is static it creates Checkbox but above the window size doesn't show, i want to add scroll to show all Checkbox and select which user want, how can i do that? [It is the second window after we passing and selecting some fields from first window, self.main_query is the query which is selected from first page by user]
import sys
from PyQt5.QtWidgets import QScrollBar, QSlider, QMainWindow, QApplication, QPushButton, QWidget, QAction, QTabWidget, QVBoxLayout, QLabel, QCheckBox
from PyQt5 import QtGui
from PyQt5.QtCore import pyqtSlot
import pymysql
class FormTwo(QWidget):
def __init__(self):
super().__init__()
self.title = 'Second Page which Showing Analytics'
self.title = 'First Main Window'
self.left = 0
self.top = 0
self.width = 700
self.height = 600
self.main_query = " select data from database where "
self.initform2ui()
self.show()
def initform2ui(self):
conn = pymysql.connect(host = 'localhost', user = 'root', password = '********', db = 'db_name')
cur4 = conn.cursor()
query_for_analytics = "select distinct Analytics from analyticsreport"
cur4.execute(query_for_analytics)
self.no_of_analytics = cur4.rowcount
result = cur4.fetchall()
checkbox = 'checkbox3'
r_move = 95
c_move = 75
myFont = QtGui.QFont()
myFont.setBold(True)
self.label2 = QLabel('Analytics', self)
self.label2.setFont(myFont)
self.label2.setStyleSheet('QLabel {Color:blue}')
self.label2.move(100, 50)
self.layout = QVBoxLayout()
#self.layout.addWidget(self.tableWidget)
self.s1 = QSlider()
self.setLayout(self.layout)
self.setWindowTitle('Proceed for the result of Analytics')
self.setGeometry(self.top, self.left, self.width, self.height)
self.button1 = QPushButton('Proceed For Result', self)
self.button1.setStyleSheet('background-color:darkblue; color: white')
self.button1.move(140,300)
self.button1.clicked.connect(self.on_button_pushed)
self.list_of_checkbox_for_analytics = []
for i in range(self.no_of_analytics):
name = str(list(result[i]))
print("name", name)
name = name.replace("[", "")
name = name.replace("]", "")
name = name.replace("'", "")
cb1 = checkbox + str(i)
self.list_of_checkbox_for_analytics.append(name)
self.list_of_checkbox_for_analytics[i] = QCheckBox(name, self)
self.list_of_checkbox_for_analytics[i].adjustSize()
self.list_of_checkbox_for_analytics[i].move(r_move, c_move)
c_move = c_move + 20
def on_button_pushed(self):
initialize_ai = 0
flag = 0
ana_query = ''
for i in range(self.no_of_analytics):
if self.list_of_checkbox_for_analytics[i].isChecked():
print("Checked", self.list_of_checkbox_for_analytics[i].text())
flag = 1
if initialize_ai == 0 and flag == 1:
ana_query = " '" + self.list_of_checkbox_for_analytics[i].text() + "' "
initialize_ai = initialize_ai + 1
flag = 0
if initialize_ai > 0 and flag == 1:
ana_query = ana_query + " or '" + self.list_of_checkbox_for_analytics[i].text() + "' "
flag = 0
if len(ana_query)>2:
ana_query = " and (Analytics = " + ana_query + ")"
main_query = self.main_query + ana_query
else:
main_query = self.main_query
print(main_query)
self.window = QMainWindow()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = FormTwo()
sys.exit(app.exec_())
You have to use a QScrollArea, on the other hand to handle the positions in these cases it is advisable to use layouts.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import pymysql
class FormTwo(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.title = 'Second Page which Showing Analytics'
self.left, self.top, self.width, self.height = 0, 0, 700, 600
self.main_query = " select data from database where "
self.initform2ui()
self.show()
def initform2ui(self):
self.setWindowTitle('Proceed for the result of Analytics')
self.setGeometry(self.top, self.left, self.width, self.height)
myFont = QtGui.QFont()
myFont.setBold(True)
self.label2 = QtWidgets.QLabel('Analytics')
self.label2.setFont(myFont)
self.label2.setStyleSheet('QLabel {Color:blue}')
self.button1 = QtWidgets.QPushButton('Proceed For Result')
self.button1.setStyleSheet('background-color:darkblue; color: white')
self.button1.clicked.connect(self.on_button_pushed)
self.list_of_checkbox_for_analytics = []
scrollArea = QtWidgets.QScrollArea()
content_widget = QtWidgets.QWidget()
scrollArea.setWidget(content_widget)
scrollArea.setWidgetResizable(True)
lay = QtWidgets.QVBoxLayout(content_widget)
conn = pymysql.connect(host = 'localhost', user = 'root', password = '********', db = 'db_name')
cur = conn.cursor()
query_for_analytics = "select distinct Analytics from analyticsreport"
cur.execute(query_for_analytics)
for row in cur.fetchall():
name = str(list(row))
name = name.replace("[", "").replace("]", "").replace("'", "")
checkbox = QtWidgets.QCheckBox(name)
checkbox.adjustSize()
lay.addWidget(checkbox)
self.list_of_checkbox_for_analytics.append(checkbox)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.label2)
layout.addWidget(self.button1)
layout.addWidget(scrollArea)
#QtCore.pyqtSlot()
def on_button_pushed(self):
initialize_ai = 0
flag = False
ana_query = ''
for checkbox in self.list_of_checkbox_for_analytics:
if checkbox.isChecked():
print("Checked", checkbox.text())
flag = True
if initialize_ai == 0 and flag:
ana_query = " '" + checkbox.text() + "' "
initialize_ai += 1
flag = False
if initialize_ai > 0 and flag:
ana_query += " or '" + checkbox.text() + "' "
flag = False
main_query = self.main_query
if len(ana_query) > 2:
ana_query = " and (Analytics = " + ana_query + ")"
main_query += ana_query
print(main_query)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = FormTwo()
sys.exit(app.exec_())
Related
How to make an Angled arrow-type border in PyQt QFrame? In My code, I Have two QLabels and respective frames. My aim is to make an arrow shape border on right side of every QFrame.For clear-cut idea, attach a sample picture.
import sys
from PyQt5.QtWidgets import *
class Angle_Border(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Angle Border")
self.lbl1 = QLabel("Python")
self.lbl2 = QLabel("PyQt")
self.frame1 = QFrame()
self.frame1.setProperty("type","1")
self.frame1.setFixedSize(200,50)
self.frame1.setStyleSheet("background-color:red;color:white;"
"font-family:Trebuchet MS;font-size: 15pt;text-align: center;"
"border-top-right-radius:25px solid ; border-bottom-right-radius:25px solid ;")
self.frame2 = QFrame()
self.frame2.setFixedSize(200, 50)
self.frame2.setStyleSheet("background-color:blue;color:white;"
"font-family:Trebuchet MS;font-size: 15pt;text-align: center;"
"border-top:1px solid transparent; border-bottom:1px solid transparent;")
self.frame_outer = QFrame()
self.frame_outer.setFixedSize(800, 60)
self.frame_outer.setStyleSheet("background-color:green;color:white;"
"font-family:Trebuchet MS;font-size: 15pt;text-align: center;")
self.frame1_layout = QHBoxLayout(self.frame1)
self.frame2_layout = QHBoxLayout(self.frame2)
self.frame_outer_layout = QHBoxLayout(self.frame_outer)
self.frame_outer_layout.setContentsMargins(5,0,0,0)
self.frame1_layout.addWidget(self.lbl1)
self.frame2_layout.addWidget(self.lbl2)
self.hbox = QHBoxLayout()
self.layout = QHBoxLayout()
self.hbox.addWidget(self.frame1)
self.hbox.addWidget(self.frame2)
self.hbox.addStretch()
self.hbox.setSpacing(0)
# self.layout.addLayout(self.hbox)
self.frame_outer_layout.addLayout(self.hbox)
self.layout.addWidget(self.frame_outer)
self.setLayout(self.layout)
def main():
app = QApplication(sys.argv)
ex = Angle_Border()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Sample Picture
Since the OP didn't ask for user interaction (mouse or keyboard), a possible solution could use the existing features of Qt, specifically QSS (Qt Style Sheets).
While the currently previously accepted solution does follow that approach, it's not very effective, most importantly because it's basically "static", since it always requires knowing the color of the following item in order to define the "arrow" colors.
This not only forces the programmer to always consider the "sibling" items, but also makes extremely (and unnecessarily) complex the dynamic creation of such objects.
The solution is to always (partially) "redo" the layout and update the stylesheets with the necessary values, which consider the current size (which shouldn't be hardcoded), the following item (if any) and carefully using the layout properties and "spacer" stylesheets based on the contents.
The following code uses a more abstract, dynamic approach, with basic functions that allow adding/insertion and removal of items. It still uses a similar QSS method, but, with almost the same "line count", it provides a simpler and much more intuitive approach, allowing item creation, deletion and modification with single function calls that are much easier to use.
A further benefit of this approach is that implementing "reverse" arrows is quite easy, and doesn't break the logic of the item creation.
Considering all the above, you can create an actual class that just needs basic calls such as addItem() or removeItem().
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class ArrowMenu(QWidget):
vMargin = -1
hMargin = -1
def __init__(self, items=None, parent=None):
super().__init__(parent)
layout = QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addStretch()
self.items = []
if isinstance(items, dict):
self.addItems(items.items())
elif items is not None:
self.addItems(items)
def addItems(self, items):
for item in items:
if isinstance(item, str):
self.addItem(item)
else:
self.addItem(*item)
def addItem(self, text, background=None):
self.insertItem(len(self.items), text, background)
def insertItem(self, index, text, background=None):
label = QLabel(text)
if background is None:
background = self.palette().window().color()
background.setAlpha(0)
else:
background = QColor(background)
# human eyes perceive "brightness" in different ways, let's compute
# that value in order to decide a color that has sufficient contrast
# with the background; see https://photo.stackexchange.com/q/10412
r, g, b, a = background.getRgbF()
brightness = r * .3 + g * .59 + b * .11
foreground = 'black' if brightness >= .5 else 'white'
label.setStyleSheet('color: {}; background: {};'.format(
foreground, background.name(background.HexArgb)))
layout = self.layout()
if index < len(self.items):
i = 0
for _label, _spacer, _ in self.items:
if i == index:
i += 1
layout.insertWidget(i * 2, _label)
layout.insertWidget(i * 2 + 1, _spacer)
i += 1
layout.insertWidget(index * 2, label)
spacer = QWidget(objectName='menuArrow')
layout.insertWidget(index * 2 + 1, spacer)
self.items.insert(index, (label, spacer, background))
self.updateItems()
def removeItem(self, index):
label, spacer, background = self.items.pop(index)
label.deleteLater()
spacer.deleteLater()
layout = self.layout()
for i, (label, spacer, _) in enumerate(self.items):
layout.insertWidget(i * 2, label)
layout.insertWidget(i * 2 + 1, spacer)
self.updateItems()
self.updateGeometry()
def updateItems(self):
if not self.items:
return
size = self.fontMetrics().height()
if self.vMargin < 0:
vSize = size * 2
else:
vSize = size + self.vMargin * 2
spacing = vSize / 2
self.setMinimumHeight(vSize)
if self.hMargin >= 0:
labelMargin = self.hMargin * 2
else:
labelMargin = size // 2
it = iter(self.items)
prevBackground = prevSpacer = None
while True:
try:
label, spacer, background = next(it)
label.setContentsMargins(labelMargin, 0, labelMargin, 0)
spacer.setFixedWidth(spacing)
except StopIteration:
background = QColor()
break
finally:
if prevBackground:
if background.isValid():
cssBackground = background.name(QColor.HexArgb)
else:
cssBackground = 'none'
if prevBackground.alpha():
prevBackground = prevBackground.name(QColor.HexArgb)
else:
mid = QColor(prevBackground)
mid.setAlphaF(.5)
prevBackground = '''
qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop:0 {}, stop:1 {})
'''.format(
prevBackground.name(QColor.HexArgb),
mid.name(QColor.HexArgb),
)
prevSpacer.setStyleSheet('''
ArrowMenu > .QWidget#menuArrow {{
background: transparent;
border-top: {size}px solid {background};
border-bottom: {size}px solid {background};
border-left: {spacing}px solid {prevBackground};
}}
'''.format(
size=self.height() // 2,
spacing=spacing,
prevBackground=prevBackground,
background=cssBackground
))
prevBackground = background
prevSpacer = spacer
def resizeEvent(self, event):
self.updateItems()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
items = (
('Python', 'green'),
('Will delete', 'chocolate'),
('PyQt5', 'red'),
('Java', 'blue'),
('ASP.Net', 'yellow'),
)
ex = ArrowMenu(items)
ex.show()
QTimer.singleShot(2000, lambda: ex.addItem('New item', 'aqua'))
QTimer.singleShot(5000, lambda: ex.removeItem(1))
sys.exit(app.exec_())
And here is the result:
import sys
from PyQt5.QtWidgets import QWidget,QHBoxLayout,QLabel,QFrame,QApplication,QSizePolicy
from PyQt5.QtCore import Qt
class MyFrame(QWidget):
def __init__(self,base_color,top_color,width,edge,text,text_color):
super().__init__()
self.base_color = base_color
self.top_color = top_color
self.width = width
self.edge = edge
self.text = text
self.text_color = text_color
self.lbl = QLabel()
self.lbl.setText(self.text)
self.lbl.setFixedHeight(self.width*2)
self.lbl.setMinimumWidth((QSizePolicy.MinimumExpanding)+100)
self.lbl.setContentsMargins(0,0,0,0)
self.lbl.setAlignment(Qt.AlignCenter)
self.lbl.setStyleSheet(f"QLabel"
f"{{background-color: {self.base_color};"
f"color:{self.text_color};"
f"font-family:Trebuchet MS;"
f"font-size: 15pt;}}")
self.frame_triangle = QFrame()
self.frame_triangle.setFixedSize(self.width, self.width * 2)
self.frame_triangle.setContentsMargins(0,0,0,0)
self.hbox = QHBoxLayout()
self.hbox.setSpacing(0)
self.hbox.setContentsMargins(0,0,0,0)
self.setLayout(self.hbox)
if self.edge == "right":
self.border = "border-left"
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.frame_triangle)
elif self.edge == "left":
self.border = "border-right"
self.hbox.addWidget(self.frame_triangle)
self.hbox.addWidget(self.lbl)
elif self.edge == "none":
self.border = "border-right"
self.hbox.addWidget(self.lbl)
self.lbl.setMinimumWidth((QSizePolicy.MinimumExpanding) + 150)
self.frame_triangle.setStyleSheet(f"QFrame"
f"{{background-color: {self.base_color};"
f"border-top:100px solid {self.top_color};"
f"{self.border}:100px solid {self.base_color};"
f"border-bottom:100px solid {self.top_color};"
f"}}")
class Main_Frame(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Angled Frame")
triangle_size = 50
self.frame1 = MyFrame("lightgrey","green",triangle_size,"right","","lightgrey")
self.frame2 = MyFrame("green","red",triangle_size,"right","Python","white")
self.frame3 = MyFrame("red","blue",triangle_size,"right","PyQt5","white")
self.frame4 = MyFrame("blue","yellow",triangle_size,"right","Java","white")
self.frame5 = MyFrame("yellow","lightgrey",triangle_size,"right","ASP.Net","black")
self.frame_overall = QFrame()
self.frame_overall.setStyleSheet("background-color:lightgrey;")
self.frame_overall.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Maximum)
self.frame_overall_layout = QHBoxLayout(self.frame_overall)
self.frame_overall_layout.setSpacing(0)
# self.frame_overall_layout.addWidget(self.frame1)
self.frame_overall_layout.addWidget(self.frame2)
self.frame_overall_layout.addWidget(self.frame3)
self.frame_overall_layout.addWidget(self.frame4)
self.frame_overall_layout.addWidget(self.frame5)
self.vbox = QHBoxLayout()
self.vbox.setContentsMargins(0,0,0,0)
self.vbox.setSpacing(0)
self.vbox.addStretch()
self.vbox.addWidget(self.frame_overall)
self.vbox.addStretch()
self.setLayout(self.vbox)
def main():
app = QApplication(sys.argv)
ex = Main_Frame()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
It seems that this link can anwser your question. However, I adopt a python version for you.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QColor, QPainter, QPen, QPainterPath, QBrush
class Angle_Border(QWidget):
def __init__(self, firstButtonX, firstButtonY, buttonWidth, buttonHeight, triangleWidth, labels, colors):
super().__init__()
self.firstButtonX = firstButtonX
self.firstButtonY = firstButtonY
self.buttonWidth = buttonWidth
self.buttonHeight = buttonHeight
self.triangleWidth = triangleWidth
self.labels = labels
self.colors = colors
self.button_lists = []
for i, text_i in enumerate(self.labels):
button_i = QPushButton(text_i, self)
self.button_lists.append(button_i)
button_i.setGeometry(self.firstButtonX + (self.buttonWidth+self.triangleWidth)*i, self.firstButtonY,
self.buttonWidth, self.buttonHeight)
button_i.setStyleSheet("background-color: %s;border-style: outset;border-width: 0px;" % (QColor(self.colors[i]).name()))
# button_i.setStyleSheet("border-style: outset;border-width: 0px;")
def paintEvent(self, event):
super().paintEvent(event)
painter = QPainter(self)
for i, button_i in enumerate(self.button_lists):
x = button_i.pos().x()
y = button_i.pos().y()
w = button_i.width()
h = button_i.height()
r = QRect(x+w, y, self.triangleWidth, h)
#
# _____p1
# | \ p3
# |_____ /
# p2
point3X = x + w + self.triangleWidth
point3Y = y + h/2
point1X = x + w
point1Y = y
point2X = x + w
point2Y = y + h
path = QPainterPath()
path.moveTo(point1X, point1Y)
path.lineTo(point2X, point2Y)
path.lineTo(point3X, point3Y)
painter.setPen(QPen(Qt.NoPen))
if i != len(self.button_lists) - 1:
painter.fillRect(r, QBrush(self.colors[i+1]))
painter.fillPath(path, QBrush(self.colors[i]))
def main():
app = QApplication(sys.argv)
firstButtonX = 0
firstButtonY = 0
buttonWidth = 50
buttonHeight = 30
triangleWidth = 30
labels = ["step1", "step2", "step3"]
colors = [Qt.red, Qt.blue, Qt.yellow]
ex = Angle_Border(firstButtonX, firstButtonY, buttonWidth, buttonHeight, triangleWidth, labels, colors)
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Which gives:
You can use QTabBar and override its paint event.
For better display of the last tab, we also override the size hint functions in order to have enough space to show the last arrow without clipping it or drawing over the text.
class ArrowTabBar(QTabBar):
def sizeHint(self):
hint = super().sizeHint()
if self.count():
hint.setWidth(hint.width() + hint.height() * .2)
return hint
def minimumTabSizeHint(self, index):
hint = super().minimumTabSizeHint(index)
if index == self.count() - 1:
hint.setWidth(hint.width() + hint.height() * .2)
return hint
def tabSizeHint(self, index):
hint = super().tabSizeHint(index)
if index == self.count() - 1:
hint.setWidth(hint.width() + hint.height() * .2)
return hint
def paintEvent(self, event):
count = self.count()
if not count:
return
qp = QPainter(self)
qp.setRenderHint(qp.Antialiasing)
bottom = self.height()
midY = bottom // 2
midX = midY / 2.5
bottom -= 1
palette = self.palette()
textColor = palette.windowText().color()
normal = palette.mid()
current = palette.dark()
for i in range(count):
rect = self.tabRect(i)
path = QPainterPath()
x = rect.x()
right = rect.right()
if i:
path.moveTo(x - midX, bottom)
path.lineTo(x + midX, midY)
path.lineTo(x - midX, 0)
else:
path.moveTo(x, bottom)
path.lineTo(x, 0)
path.lineTo(right - midX, 0)
path.lineTo(right + midX, midY)
path.lineTo(right - midX, bottom)
if i == self.currentIndex():
qp.setBrush(current)
else:
qp.setBrush(normal)
qp.setPen(Qt.NoPen)
qp.drawPath(path)
qp.setPen(textColor)
qp.drawText(rect, Qt.AlignCenter|Qt.TextShowMnemonic,
self.tabText(i))
app = QApplication([])
panel = ArrowTabBar()
for i in range(5):
panel.addTab('Item {}'.format(i + 1))
panel.show()
app.exec()
I am trying to create a basic 25 key keyboard in pyqt, I have laid out the 15 white keys but am struggling with how to add the 10 remaining black keys,
This is how I made my keys
from PyQt5.QtWidgets import QApplication, QPushButton
app = QApplication([])
top_win = QWidget()
set_color(top_win, Qt.cyan)
top_win.setAutoFillBackground(True)
top_win.show()
top_win.resize(1920,1080)
top_win.setWindowTitle("Synth-01")
top_vlayout = QVBoxLayout()
top_win.setLayout(top_vlayout)
keyboard = QWidget()
keyboard.setMaximumWidth(1410)
top_vlayout.addWidget(keyboard)
keyboard_layout = QHBoxLayout()
keyboard.setAutoFillBackground(True)
keyboard.setLayout(keyboard_layout)
for i in range(15):
name = "key_" + str(i)
name = QPushButton()
name.setMaximumWidth(94)
name.setMaximumHeight(349)
keyboard_layout.addWidget(name)
I now want to add the black keys inbetween like this
In this case, it is most preferable to use QGraphicsScene with QGraphicsItem, for this case I will use svg:
from PyQt5 import QtCore, QtGui, QtWidgets, QtSvg
class PianoKey(QtWidgets.QGraphicsRectItem):
def __init__(self, black=False, rect = QtCore.QRectF(), parent=None):
super(PianoKey, self).__init__(rect, parent)
self.m_pressed = False
self.m_selectedBrush = QtGui.QBrush()
self.m_brush = QtGui.QBrush(QtCore.Qt.black) if black else QtGui.QBrush(QtCore.Qt.white)
self.m_black = black
def setPressedBrush(self, brush):
self.m_selectedBrush = brush
def paint(self, painter, option, widget):
rendered = QtSvg.QSvgRenderer("key.svg")
black_pen = QtGui.QPen(QtCore.Qt.black, 1)
gray_pen = QtGui.QPen(QtGui.QBrush(QtCore.Qt.gray), 1,
QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)
if self.m_pressed:
if self.m_selectedBrush.style() != QtCore.Qt.NoBrush:
painter.setBrush(self.m_selectedBrush)
else:
painter.setBrush(QtWidgets.QApplication.palette().highlight())
else:
painter.setBrush(self.m_brush);
painter.setPen(black_pen)
painter.drawRoundedRect(self.rect(), 15, 15, QtCore.Qt.RelativeSize)
if self.m_black:
rendered.render(painter, self.rect())
else:
points = [
QtCore.QPointF(self.rect().left()+1.5, self.rect().bottom()-1),
QtCore.QPointF(self.rect().right()-1, self.rect().bottom()-1),
QtCore.QPointF(self.rect().right()-1, self.rect().top()+1)
]
painter.setPen(gray_pen)
painter.drawPolyline(QtGui.QPolygonF(points))
def mousePressEvent(self, event):
self.m_pressed = True
self.update()
super(PianoKey, self).mousePressEvent(event)
event.accept()
def mouseReleaseEvent(self, event):
self.m_pressed = False
self.update()
super(PianoKey, self).mouseReleaseEvent(event)
KEYWIDTH, KEYHEIGHT = 18, 72
class PianoKeyBoard(QtWidgets.QGraphicsView):
def __init__(self, num_octaves=2, parent=None):
super(PianoKeyBoard, self).__init__(parent)
self.initialize()
self.m_numOctaves = num_octaves
scene = QtWidgets.QGraphicsScene(QtCore.QRectF(0, 0, KEYWIDTH * self.m_numOctaves * 7, KEYHEIGHT), self)
self.setScene(scene)
numkeys = self.m_numOctaves * 12
for i in range(numkeys):
octave = i//12*7
j = i % 12
if j >= 5: j += 1
if j % 2 == 0:
x = (octave + j/2)*KEYWIDTH
key = PianoKey(rect=QtCore.QRectF(x, 0, KEYWIDTH, KEYHEIGHT), black=False)
else:
x = (octave + j//2) * KEYWIDTH + KEYWIDTH * 6//10 + 1
key = PianoKey(rect=QtCore.QRectF(x, 0, KEYWIDTH * 8//10 - 1, KEYHEIGHT * 6//10 ), black=True)
key.setZValue(1)
key.setPressedBrush(QtWidgets.QApplication.palette().highlight())
self.scene().addItem(key)
def initialize(self):
self.setAttribute(QtCore.Qt.WA_InputMethodEnabled, False)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground)
self.setViewportUpdateMode(QtWidgets.QGraphicsView.MinimalViewportUpdate)
self.setRenderHints(QtGui.QPainter.Antialiasing|
QtGui.QPainter.TextAntialiasing |
QtGui.QPainter.SmoothPixmapTransform)
self.setOptimizationFlag(QtWidgets.QGraphicsView.DontClipPainter, True)
self.setOptimizationFlag(QtWidgets.QGraphicsView.DontSavePainterState, True)
self.setOptimizationFlag(QtWidgets.QGraphicsView.DontAdjustForAntialiasing, True)
self.setBackgroundBrush(QtWidgets.QApplication.palette().base())
def resizeEvent(self, event):
super(PianoKeyBoard, self).resizeEvent(event)
self.fitInView(self.scene().sceneRect(), QtCore.Qt.KeepAspectRatio)
def sizeHint(self):
return self.mapFromScene(self.sceneRect()).boundingRect().size()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
w = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(w)
lay.addWidget(QtWidgets.QLabel("Piano Keyboard", alignment=QtCore.Qt.AlignCenter))
lay.addWidget(PianoKeyBoard())
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
The complete code + key.svg can be found on this link
Here in my sample code i want to display my dictionary data into scroll Area.I tried so many ways but i am not getting properly.i did n't get any error also.Can any one please tell me why my data is not displayed in scroll area.where i did the mistake in below program please guide me.Thank you in advance.
Given below is my sample code:
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.products_list = {
"Givers":{
"price": 140,
"Quantity": 100,
"Discount": 0,
"Total_price":14000,
"Paid_amount":14000},
"New_Member":{
"price": 1200,
"Quantity": 10,
"Discount": 0,
"Total_price":12000,
"Paid_amount":12000},
"YearMembers_Ribbons":{
"price": 110,
"Quantity": 0,
"Discount": 0,
"Total_price":1100,
"Paid_amount":1100}
}
self.grid = QtGui.QGridLayout(self)
hbox = QtGui.QHBoxLayout()
self.clbtn = QtGui.QPushButton('close')
self.clbtn.clicked.connect(self.close)
self.lab = QtGui.QLabel("orders")
hbox.addWidget(self.lab,alignment = QtCore.Qt.AlignCenter)
hbox.addStretch()
hbox.addWidget(self.clbtn,alignment = QtCore.Qt.AlignRight)
self.grid.addLayout(hbox,0,0)
self.line = QtGui.QFrame(frameShape=QtGui.QFrame.HLine)
self.grid.addWidget(self.line,1,0)
self.main_hbox = QtGui.QHBoxLayout()
self.scroll = QtGui.QScrollArea()
self.show()
self.VBox = QtGui.QVBoxLayout()
self.Date = QtGui.QLabel("25-2-2018",objectName="small",alignment = QtCore.Qt.AlignRight)
self.v_city = QtGui.QLabel("bangalore",alignment = QtCore.Qt.AlignCenter)
self.v_state = QtGui.QLabel("karnataka",alignment = QtCore.Qt.AlignCenter)
self.v_pincode = QtGui.QLabel("560003",alignment = QtCore.Qt.AlignCenter)
self.v_country = QtGui.QLabel("India",alignment = QtCore.Qt.AlignCenter)
self.VBox.addWidget(self.Date)
self.VBox.addWidget(self.v_city)
self.VBox.addWidget(self.v_state)
self.VBox.addWidget(self.v_pincode)
self.VBox.addWidget(self.v_country)
self.main_hbox.addLayout(self.VBox)
self.main_hbox.addWidget(self.scroll)
self.grid.addLayout(self.main_hbox,2,0)
w2 = QtGui.QWidget()
self.scroll.setWidget(w2)
grid1 = QtGui.QGridLayout(w2)
self.items_Vboxlay = QtGui.QVBoxLayout()
self.vbox2 = QtGui.QVBoxLayout()
for key, value in self.products_list.items():
keys = [ vk for vk in value.keys()]
values = [ vv for vv in value.values()]
self.item_label = QtGui.QLabel(str(key), objectName="small")
self.vbox2.addWidget(self.item_label)
self.hbox1 = QtGui.QHBoxLayout()
self.hbox2 = QtGui.QHBoxLayout()
self.price = QtGui.QLabel(keys[1] + ": " + u'\u20B9 ' +str(values[1]))
self.qnty = QtGui.QLabel(keys[3] + ": " + str(values[3]))
self.discount = QtGui.QLabel(keys[0] + ": " + u'\u20B9 ' + str(values[0]))
self.totalprice = QtGui.QLabel(keys[2] + ": " + u'\u20B9 ' + str(values[2]))
self.status = QtGui.QLabel("Status" + ": "+ "Created")
self.ref_amount = QtGui.QLabel("Refund Amount"+": "+ "0")
self.ref_status = QtGui.QLabel("Refund Status"+": "+ "False")
self.hbox1.addWidget(self.price)
self.hbox1.addWidget(self.qnty)
self.hbox1.addWidget(self.discount)
self.hbox1.addWidget(self.totalprice)
self.hbox2.addWidget(self.status)
self.hbox2.addWidget(self.ref_amount)
self.hbox2.addWidget(self.ref_status)
self.line4 = QtGui.QFrame()
self.line4.setFrameShape(QtGui.QFrame.HLine)
self.vbox2.addLayout(self.hbox1)
self.vbox2.addLayout(self.hbox2)
self.vbox2.addWidget(self.line4)
self.items_Vboxlay.addLayout(self.vbox2)
grid1.addLayout(self.items_Vboxlay,0,0)
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
ex.resize(500,300)
sys.exit(app.exec_())
if __name__ == '__main__':
main()
When a widget is set in a ScrollArea the size it uses is that of the widget at that moment, in your case it does not have any size so the widget will have size 0, 0 and although you add child widgets through a QScrollArea layout, it does not will take into account, so for QScrollArea to monitor the size you must enable the widgetResizable property:
self.scroll = QtGui.QScrollArea(widgetResizable=True)
I am trying to set a custom property of an image inserted into a QTextEdit. I have the following example code which sets then outputs the value of the property to the terminal:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class TestEditor(QWidget):
def __init__(self):
QWidget.__init__(self)
layout = QVBoxLayout()
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.textEdit = QTextEdit()
self.layout().addWidget(self.textEdit)
document = self.textEdit.document()
cursor = QTextCursor(document)
cursor.insertImage("./testimage.png")
f = cursor.charFormat()
print(f)
prop_id = 0x100000 + 1
f.setProperty(prop_id, 100)
print(f.intProperty(prop_id))
print('------')
block = document.firstBlock()
while block.length() > 0:
print(block)
it = block.begin()
while not it.atEnd():
f = it.fragment()
fmt = f.charFormat()
print(fmt)
print(fmt.intProperty(prop_id))
it += 1
block = block.next()
class TestWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.initUi()
def initUi(self):
layout = QVBoxLayout()
layout.addWidget(HextEditor())
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.setWindowTitle('button tooltip')
self.show()
def main():
app = QApplication(sys.argv)
window = TestWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The program results in an output of:
<PyQt5.QtGui.QTextCharFormat object at 0x107109ba8>
100
------
<PyQt5.QtGui.QTextBlock object at 0x105448318>
<PyQt5.QtGui.QTextCharFormat object at 0x107109ba8>
0
Note that the second time the value is gotten it has a value of 0 rather than 100. It even appears to be the same instance of a QTextCharFormat. How would I accomplish something like this? Am I missing something simple here?
I solved this by saving the range of the inserted image, selecting it, and using QTextCursor.setCharFormat() to save the changes:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class TestEditor(QWidget):
def __init__(self):
QWidget.__init__(self)
layout = QVBoxLayout()
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.textEdit = QTextEdit()
self.layout().addWidget(self.textEdit)
document = self.textEdit.document()
cursor = QTextCursor(document)
# Save the position of the beginning and end of the inserted image
p1 = cursor.position()
cursor.insertImage("./testimage.png")
p2 = cursor.position()
f = cursor.charFormat()
print(f)
prop_id = 0x100000 + 1
f.setProperty(prop_id, 100)
# Select the inserted fragment and apply format
cursor.setPosition(p1)
cursor.setPosition(p2, QTextCursor.KeepAnchor)
cursor.setCharFormat(f)
print(f.intProperty(prop_id))
print('------')
block = document.firstBlock()
while block.length() > 0:
print(block)
it = block.begin()
while not it.atEnd():
f = it.fragment()
fmt = f.charFormat()
print(fmt)
print(fmt.intProperty(prop_id))
it += 1
block = block.next()
class TestWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.initUi()
def initUi(self):
layout = QVBoxLayout()
layout.addWidget(TestEditor())
self.setLayout(layout)
self.layout().setSpacing(0)
self.layout().setContentsMargins(0, 0, 0, 0)
self.setWindowTitle('button tooltip')
self.show()
def main():
app = QApplication(sys.argv)
window = TestWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I've been working on an XCOPY GUI and I added in check boxes to select the desired xcopy switches. I have it all working, but I'm trying to condense the code as I'm sure there is a way to do it, I'm just not sure how. Basically, for each switch (E, C, H, Y, I) I do a function call to check the state of the CheckBox and return the value for my x_copy function's subprocess call.
How could I go about making a call to a single function and have it check the states of all my checkbox widgets?
import sys
from PyQt4 import QtGui
import os
import subprocess
class XcopyMain(QtGui.QWidget):
def __init__(self):
super(XcopyMain, self).__init__()
# Declare Widgets
src_btn = QtGui.QPushButton('Source')
dst_btn = QtGui.QPushButton('Destination')
prev_btn = QtGui.QPushButton('Preview File(s)')
x_copy_btn = QtGui.QPushButton('Start XCOPY')
switch_lbl = QtGui.QLabel('Switches:')
# self.progress = QtGui.QProgressBar(self)
self.src_line = QtGui.QLineEdit()
self.dst_line = QtGui.QLineEdit()
self.selected_files = QtGui.QTextEdit()
self.e_chk = QtGui.QCheckBox('E')
self.e_chk.stateChanged.connect(self.e_apply)
self.c_chk = QtGui.QCheckBox('C')
self.c_chk.stateChanged.connect(self.c_apply)
self.h_chk = QtGui.QCheckBox('H')
self.h_chk.stateChanged.connect(self.h_apply)
self.y_chk = QtGui.QCheckBox('Y')
self.y_chk.stateChanged.connect(self.y_apply)
self.i_chk = QtGui.QCheckBox('I')
self.i_chk.stateChanged.connect(self.i_apply)
# Declare Emit / Slot
src_btn.clicked.connect(self.src_select)
dst_btn.clicked.connect(self.dst_select)
prev_btn.clicked.connect(self.list_files)
x_copy_btn.clicked.connect(self.x_copy)
# Declare Layout
mainLayout = QtGui.QGridLayout()
mainLayout.addWidget(src_btn, 0, 0)
mainLayout.addWidget(dst_btn, 0, 1)
mainLayout.addWidget(prev_btn, 2, 0)
mainLayout.addWidget(x_copy_btn, 2, 1)
mainLayout.addWidget(self.src_line, 1, 0)
mainLayout.addWidget(self.dst_line, 1, 1)
mainLayout.addWidget(self.selected_files, 3, 0)
mainLayout.addWidget(switch_lbl, 0, 2)
mainLayout.addWidget(self.e_chk, 1, 2)
mainLayout.addWidget(self.c_chk, 2, 2)
mainLayout.addWidget(self.h_chk, 3, 2)
mainLayout.addWidget(self.y_chk, 4, 2)
mainLayout.addWidget(self.i_chk, 5, 2)
# mainLayout.addWidget(self.progress,4,0)
self.setLayout(mainLayout)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('X Copy 3.0')
self.show()
def src_select(self):
src_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.src_line.setText(src_fldr)
def dst_select(self):
dst_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.dst_line.setText(dst_fldr)
def list_files(self):
src_path = self.src_line.text()
for f in (os.listdir(src_path)):
self.selected_files.append(f)
def x_copy(self):
src_path = self.src_line.text()
dst_path = self.dst_line.text()
#print(src_path + ' plus ' + dst_path + ' plus ' + self.attr_check())
subprocess.call(['xcopy', src_path, dst_path, '/' + self.e_apply() + '/' +
self.c_apply() + '/' +
self.h_apply() + '/' +
self.y_apply() + '/' +
self.i_apply()])
def e_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'E'
else:
print('E not selected')
def c_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'C'
else:
print('C not selected')
def h_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'H'
else:
print('H not selected')
def y_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'Y'
else:
print('Y not selected')
def i_apply(self):
state = self.e_chk.checkState()
if state == 2:
return 'I'
else:
print('I not selected')
app = QtGui.QApplication(sys.argv)
mainWindow = XcopyMain()
status = app.exec_()
sys.exit(status)
The task that you have been able to implement can be done in a more elegant way. We can use the sender() function that returns the object that generates the signal
def chk_box_value(self, state):
k = '/'+self.sender().text()
if state == QtCore.Qt.Checked: # similar to 2
self.myList.append(k)
elif state == QtCore.Qt.Unchecked: # similar to 0
self.myList.remove(k)
Complete Code:
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
import os
import subprocess
class XcopyMain(QtGui.QWidget):
def __init__(self):
super(XcopyMain, self).__init__()
self.myList = []
# Declare Widgets
src_btn = QtGui.QPushButton('Source')
dst_btn = QtGui.QPushButton('Destination')
prev_btn = QtGui.QPushButton('Preview File(s)')
x_copy_btn = QtGui.QPushButton('Start XCOPY')
switch_lbl = QtGui.QLabel('Switches:')
# self.progress = QtGui.QProgressBar(self)
self.src_line = QtGui.QLineEdit()
self.dst_line = QtGui.QLineEdit()
self.selected_files = QtGui.QTextEdit()
self.E_chk = QtGui.QCheckBox('E')
self.E_chk.stateChanged.connect(self.chk_box_value)
self.C_chk = QtGui.QCheckBox('C')
self.C_chk.stateChanged.connect(self.chk_box_value)
self.H_chk = QtGui.QCheckBox('H')
self.H_chk.stateChanged.connect(self.chk_box_value)
self.Y_chk = QtGui.QCheckBox('Y')
self.Y_chk.stateChanged.connect(self.chk_box_value)
self.I_chk = QtGui.QCheckBox('I')
self.I_chk.stateChanged.connect(self.chk_box_value)
# Declare Emit / Slot
src_btn.clicked.connect(self.src_select)
dst_btn.clicked.connect(self.dst_select)
prev_btn.clicked.connect(self.list_files)
x_copy_btn.clicked.connect(self.x_copy)
# Declare Layout
mainLayout = QtGui.QGridLayout()
mainLayout.addWidget(src_btn, 0, 0)
mainLayout.addWidget(dst_btn, 0, 1)
mainLayout.addWidget(prev_btn, 2, 0)
mainLayout.addWidget(x_copy_btn, 2, 1)
mainLayout.addWidget(self.src_line, 1, 0)
mainLayout.addWidget(self.dst_line, 1, 1)
mainLayout.addWidget(self.selected_files, 3, 0)
mainLayout.addWidget(switch_lbl, 0, 2)
mainLayout.addWidget(self.E_chk, 1, 2)
mainLayout.addWidget(self.C_chk, 2, 2)
mainLayout.addWidget(self.H_chk, 3, 2)
mainLayout.addWidget(self.Y_chk, 4, 2)
mainLayout.addWidget(self.I_chk, 5, 2)
# mainLayout.addWidget(self.progress,4,0)
self.setLayout(mainLayout)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('X Copy 3.0')
self.show()
def src_select(self):
src_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.src_line.setText(src_fldr)
def dst_select(self):
dst_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.dst_line.setText(dst_fldr)
def list_files(self):
src_path = self.src_line.text()
for f in (os.listdir(src_path)):
self.selected_files.append(f)
def x_copy(self):
src_path = self.src_line.text()
dst_path = self.dst_line.text()
#print(src_path + ' plus ' + dst_path + ' plus ' + self.attr_check())
subprocess.call(['xcopy', src_path, dst_path, "".join(self.myList)])
def chk_box_value(self, state):
k = '/'+self.sender().text()
if state == QtCore.Qt.Checked:
self.myList.append(k)
elif state == QtCore.Qt.Unchecked:
self.myList.remove(k)
app = QtGui.QApplication(sys.argv)
mainWindow = XcopyMain()
status = app.exec_()
sys.exit(status)
I found a way to combine my checkbox value checks and run it through a loop.
import sys
from PyQt4 import QtGui
import os
import subprocess
class XcopyMain(QtGui.QWidget):
def __init__(self):
super(XcopyMain, self).__init__()
# Declare Widgets
src_btn = QtGui.QPushButton('Source')
dst_btn = QtGui.QPushButton('Destination')
prev_btn = QtGui.QPushButton('Preview File(s)')
x_copy_btn = QtGui.QPushButton('Start XCOPY')
switch_lbl = QtGui.QLabel('Switches:')
# self.progress = QtGui.QProgressBar(self)
self.src_line = QtGui.QLineEdit()
self.dst_line = QtGui.QLineEdit()
self.selected_files = QtGui.QTextEdit()
self.myList = []
self.E_chk = QtGui.QCheckBox('E')
self.E_chk.stateChanged.connect(self.chk_box_value)
self.C_chk = QtGui.QCheckBox('C')
self.C_chk.stateChanged.connect(self.chk_box_value)
self.H_chk = QtGui.QCheckBox('H')
self.H_chk.stateChanged.connect(self.chk_box_value)
self.Y_chk = QtGui.QCheckBox('Y')
self.Y_chk.stateChanged.connect(self.chk_box_value)
self.I_chk = QtGui.QCheckBox('I')
self.I_chk.stateChanged.connect(self.chk_box_value)
# Declare Emit / Slot
src_btn.clicked.connect(self.src_select)
dst_btn.clicked.connect(self.dst_select)
prev_btn.clicked.connect(self.list_files)
x_copy_btn.clicked.connect(self.x_copy)
# Declare Layout
mainLayout = QtGui.QGridLayout()
subLayout = QtGui.QHBoxLayout()
mainLayout.addWidget(src_btn, 0, 0)
mainLayout.addWidget(dst_btn, 0, 1)
mainLayout.addWidget(prev_btn, 2, 0)
mainLayout.addWidget(x_copy_btn, 2, 1)
mainLayout.addWidget(self.src_line, 1, 0)
mainLayout.addWidget(self.dst_line, 1, 1)
mainLayout.addWidget(self.selected_files, 3, 0, 1, 2)
#mainLayout.addWidget(switch_lbl, 0, 2)
subLayout.addWidget(self.E_chk)
subLayout.addWidget(self.C_chk)
subLayout.addWidget(self.H_chk)
subLayout.addWidget(self.Y_chk)
subLayout.addWidget(self.I_chk)
# Declare ToolTips
QtGui.QToolTip.setFont(QtGui.QFont('SansSerif', 10))
#self.setToolTip('This switch does XXX')
self.E_chk.setToolTip('Copies directories and subdirectories, including empty ones.')
self.C_chk.setToolTip('Continues copying even if errors occur.')
self.H_chk.setToolTip('Copies hidden and system files also.')
self.Y_chk.setToolTip('Suppresses prompting to confirm you want to overwrite an existing destination file.')
self.I_chk.setToolTip('If destination does not exist and copying more than one file, assumes that destination must be a directory.')
mainLayout.addLayout(subLayout, 5, 0, 1, 5)
# mainLayout.addWidget(self.progress,4,0)
self.setLayout(mainLayout)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('X Copy 3.0')
self.show()
def src_select(self):
src_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.src_line.setText(src_fldr)
def dst_select(self):
dst_fldr = QtGui.QFileDialog.getExistingDirectory(self, 'Select Directory')
self.dst_line.setText(dst_fldr)
def list_files(self):
src_path = self.src_line.text()
for f in (os.listdir(src_path)):
self.selected_files.append(f)
def x_copy(self):
src_path = self.src_line.text()
dst_path = self.dst_line.text()
#print(src_path + ' plus ' + dst_path + ' plus ' + "".join(self.myList))
subprocess.call(['xcopy', src_path, dst_path, "".join(self.myList)])
#
def chk_box_value(self):
letter = ['/E', '/C', '/H', '/Y', '/I']
value = [self.E_chk.checkState(),
self.C_chk.checkState(),
self.H_chk.checkState(),
self.Y_chk.checkState(),
self.I_chk.checkState()]
dictionary = dict(zip(letter, value))
for k, v in dictionary.items():
if v == 2 and k not in self.myList:
self.myList.append(k)
elif v == 0 and k in self.myList:
self.myList.remove(k)
app = QtGui.QApplication(sys.argv)
mainWindow = XcopyMain()
status = app.exec_()
sys.exit(status)