是否可以使用 PYQT5 中的元素创建一个类 [英] Would it be possible to create a class using elements from PYQT5

查看:39
本文介绍了是否可以使用 PYQT5 中的元素创建一个类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个 GUI 键盘.我正在使用 QPushButton 来复制密钥.我还没有专注于将它链接到 MIDI.但是,我想知道是否可以使用 QPushButton 的属性创建一个类.我的意思是像 QPushButton.move/resize/setStyleSheet 这样的函数.

就目前而言,我的代码很长(如下所示).这是由于不断重复代码来制作每个按钮.但是,我注意到诸如大小、样式表和位置(仅在 y 轴上)等属性是相同的,主要区别在于黑白键之间的 x 轴和 y 轴.如果我要创建一个类,我将如何创建具有各种属性的对象?

再一次,如果我的逻辑有缺陷或我犯了任何错误,请随时告诉我.

导入系统从 PyQt5.QtWidgets 导入 QMainWindow、QApplication、QWidget、QPushButton、QAction、QLineEdit、QMessageBox、QLabel \,QDialog从 PyQt5.QtGui 导入 QIcon、QHideEvent、QFont、QPixmap从 PyQt5.QtCore 导入 pyqtSlot、QObject、QSize类应用程序(QMainWindow):def __init__(self):super().__init__()self.title = '钢琴'self.left = 620self.top =250self.width = 1920self.height = 1080self.initUI()定义 initUI(self):self.setWindowTitle(self.title)self.setGeometry(self.left, self.top, self.width, self.height)self.setFixedWidth(self.width)self.setFixedHeight(self.height)self.setStyleSheet("背景颜色:浅灰色")self.setWindowIcon(QIcon('img.png'))# 在窗口中创建一个按钮self.button1 = QPushButton('C', self)self.button1.move(10, 650)self.button1.setFont(QFont('Arial', 14))self.button1.resize(100,400)self.button1.setStyleSheet("background-color:white; border :1px solid ;") #Black 不工作self.button2 = QPushButton('D', self)self.button2.move(110,650)self.button2.setFont(QFont('Arial', 14))self.button2.resize(100, 400)self.button2.setStyleSheet("background-color:white; border:1px solid ;")self.button3 = QPushButton('E', self)self.button3.move(210, 650)self.button3.setFont(QFont('Arial', 14))self.button3.resize(100, 400)self.button3.setStyleSheet("background-color:white; border:1px solid ;")self.button4 = QPushButton('F', self)self.button4.move(310, 650)self.button4.setFont(QFont('Arial', 14))self.button4.resize(100, 400)self.button4.setStyleSheet("background-color:white; border:1px solid ;")self.button5 = QPushButton('G', self)self.button5.move(410, 650)self.button5.setFont(QFont('Arial', 14))self.button5.resize(100, 400)self.button5.setStyleSheet("background-color:white; border:1px solid ;")self.button6 = QPushButton('A', self)self.button6.move(510, 650)self.button6.setFont(QFont('Arial', 14))self.button6.resize(100, 400)self.button6.setStyleSheet("background-color:white; border:1px solid ;")self.button7 = QPushButton('B', self)self.button7.move(610, 650)self.button7.setFont(QFont('Arial', 14))self.button7.resize(100, 400)self.button7.setStyleSheet("background-color:white; border:1px solid ;")self.button8 = QPushButton('C2', self)self.button8.move(710, 650)self.button8.setFont(QFont('Arial', 14))self.button8.resize(100, 400)self.button8.setStyleSheet("background-color:white; border:1px solid ;")self.button2 = QPushButton('D2', self)self.button2.move(810, 650)self.button2.setFont(QFont('Arial', 14))self.button2.resize(100, 400)self.button2.setStyleSheet("background-color:white; border:1px solid ;")self.button3 = QPushButton('E2', self)self.button3.move(910, 650)self.button3.setFont(QFont('Arial', 14))self.button3.resize(100, 400)self.button3.setStyleSheet("background-color:white; border:1px solid ;")self.button4 = QPushButton('F2', self)self.button4.move(1010, 650)self.button4.setFont(QFont('Arial', 14))self.button4.resize(100, 400)self.button4.setStyleSheet("background-color:white; border:1px solid ;")self.button5 = QPushButton('G2', self)self.button5.move(1110, 650)self.button5.setFont(QFont('Arial', 14))self.button5.resize(100, 400)self.button5.setStyleSheet("background-color:white; border:1px solid ;")self.button6 = QPushButton('A2', self)self.button6.move(1210, 650)self.button6.setFont(QFont('Arial', 14))self.button6.resize(100, 400)self.button6.setStyleSheet("background-color:white; border:1px solid ;")self.button7 = QPushButton('B2', self)self.button7.move(1310, 650)self.button7.setFont(QFont('Arial', 14))self.button7.resize(100, 400)self.button7.setStyleSheet("background-color:white; border:1px solid ;")self.button8 = QPushButton('C3', self)self.button8.move(1410, 650)self.button8.setFont(QFont('Arial', 14))self.button8.resize(100, 400)self.button8.setStyleSheet("background-color:white; border:1px solid ;")self.button1up = QPushButton('C#', self)self.button1up.move(85, 650)self.button1up.setFont(QFont('Arial', 14))self.button1up.resize(50, 300)self.button1up.setStyleSheet("background-color:black; border:1px solid ;")self.button2up = QPushButton('D#', self)self.button2up.move(185, 650)self.button2up.setFont(QFont('Arial', 14))self.button2up.resize(50, 300)self.button2up.setStyleSheet("background-color:black; border:1px solid;")self.button3up = QPushButton('F#', self)self.button3up.move(385, 650)self.button3up.setFont(QFont('Arial', 14))self.button3up.resize(50, 300)self.button3up.setStyleSheet("background-color:black; border:1px solid ;")self.button4up = QPushButton('G#', self)self.button4up.move(485, 650)self.button4up.setFont(QFont('Arial', 14))self.button4up.resize(50, 300)self.button4up.setStyleSheet("background-color:black; border:1px solid;")self.button5up = QPushButton('A#', self)self.button5up.move(585, 650)self.button5up.setFont(QFont('Arial', 14))self.button5up.resize(50, 300)self.button5up.setStyleSheet("background-color:black; border:1px solid ;")self.button6up = QPushButton(self)self.button6up.move(785, 650)self.button6up.setFont(QFont('Arial', 14))self.button6up.resize(50, 300)self.button6up.setStyleSheet("background-color:black; border:1px solid;")self.button7up = QPushButton(self)self.button7up.move(885, 650)self.button7up.setFont(QFont('Arial', 14))self.button7up.resize(50, 300)self.button7up.setStyleSheet("background-color:black; border:1px solid;")self.button8up = QPushButton(self)self.button8up.move(1085, 650)self.button8up.setFont(QFont('Arial', 14))self.button8up.resize(50, 300)self.button8up.setStyleSheet("background-color:black; border:1px solid ;")self.button9up = QPushButton(self)self.button9up.move(1185, 650)self.button9up.setFont(QFont('Arial', 14))self.button9up.resize(50, 300)self.button9up.setStyleSheet("background-color:black; border:1px solid;")self.button10up = QPushButton(self)self.button10up.move(1285, 650)self.button10up.setFont(QFont('Arial', 14))self.button10up.resize(50, 300)self.button10up.setStyleSheet("background-color:black; border:1px solid ;")# 将按钮连接到函数 on_clickself.button1.clicked.connect(self.b1)自我展示()@pyqtSlot()def b1(自我):经过如果 __name__ == '__main__':app = QApplication(sys.argv)前 = 应用程序()sys.exit(app.exec_())

解决方案

第一个逻辑解决方案是为每个键创建一个数据列表,如下所示:

KeyMap = (# 键名,x,y,宽度,高度,颜色('C', 10, 650, 100, 400, '白色'),# ...('C#', 85, 650, 50, 300, '黑色'),)

然后循环遍历列表:

 baseStyle = '背景色:{};边框:1px 实心;'对于 KeyMap 中的键、x、y、宽度、高度、颜色:button = QPushButton('key', self)button.setGeometry(x, y, 宽度, 高度)button.setFont(QFont('Arial', 14))button.setStyleSheet(baseStyle.format(color)

不幸的是,虽然上面的方法对于简单的例子可能工作得很好,但我可以根据经验告诉你,它不适用于这种情况(类似钢琴的键盘),主要是由于以下两个原因:

  • 固定几何形状很少是一个好主意,如果您出于任何原因需要调整键盘大小(包括使其适合屏幕,特别是如果它很小),它会使所有东西都更难手动编码;
  • 您可能需要将键盘扩展到更多八度音程或想要更改键的宽度和高度之间的比率;

我有过尝试创建 UI 键盘的经验,我最终得到了一个完全自定义的小部件(基于 QGraphicsView),但对于简单的情况,以下可能适合您的需求.

诀窍是使用 Qt 网格布局,它具有有趣的功能"如果放置在其单元格"之间,则允许项目重叠.

以下代码为每个白键使用 2 行(一个用于顶部的白键和黑键,底部的一个用于白键)和 3 列用于每个白键:而白键使用所有三列,而黑键使用第三列前一个白键,以及下一个白键;想象一张这样的桌子:

+---+---+---+---+---+---+---+---+---+---+|· |· ||· |· ||· |C ||D |· ||· |锋利||锋利|· ||· |· ||· |· |+ · · · +---+---+ · +---+---+ · · · +|· · |· · |· · ||·C·|· D · |·E·||· · |· · |· · |+---+---+---+---+---+---+---+---+---+

然后您可以为按键创建一个基本类(包括按键触发的信号释放),并使用简单的列表轻松获取按键是白色还是黑色并放置/相应地设置样式.

可选参数显然是针对八度范围和八度开始(因为您可能要使用 MIDI,这很重要,因为您会自动获得键值).

from PyQt5 import QtCore, QtWidgetsBlackIdx = 1, 3, -1, 6, 8, 10WhiteIdx = 0, 2, 4, 5, 7, 9, 11KeyNames = 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'类 KeyButton(QtWidgets.QPushButton):触发 = QtCore.pyqtSignal(int, bool)def __init__(self, key, isBlack=False):super().__init__()self.key = 键# 这将被样式表使用self.setProperty('isBlack', isBlack)八度,keyIdx = divmod(key, 12)self.setText('{}{}'.format(KeyNames[keyIdx],octave))self.setMinimumWidth(25)self.setMinimumSize(25, 80 if isBlack else 120)# 确保键垂直扩展self.setSizePolicy(QtWidgets.QSizePolicy.Preferred,QtWidgets.QSizePolicy.Expanding)# 将按下和释放(未点击!)信号连接到我们的自定义信号self.pressed.connect(lambda: self.triggered.emit(key, True))self.released.connect(lambda: self.triggered.emit(key, False))类键盘(QtWidgets.QWidget):def __init__(self,octaves=2,octaveStart=3):super().__init__()布局 = QtWidgets.QGridLayout(self)#键高比例:白键比黑键长1/3layout.setRowStretch(0, 2)layout.setRowStretch(1, 1)layout.setSpacing(0)黑键 = []对于范围内的八度音程(八度音程):对于范围内的 k(12):isBlack = BlackIdx 中的 kkeyButton = KeyButton(k + (octaveStart + Octave) * 12, isBlack)keyButton.triggered.connect(self.keyTriggered)如果是黑色:keyPos = BlackIdx.index(k)# 列基于键列表的索引,加上 2 个单元格";col = keyPos * 3 + 2# 布局中只有一行跨度 = 1# 只有两列跨度 = 2blackKeys.append(keyButton)别的:keyPos = WhiteIdx.index(k)col = keyPos * 3# 两行跨度 = 2# 三列跨度 = 3col += 八度 * 21layout.addWidget(keyButton, 0, col, vSpan, hSpan)#空白"E-F 和 B-C 之间的垫片,以保持间距均匀efSpacer = QtWidgets.QWidget()efSpacer.setMinimumWidth(25)layout.addWidget(efSpacer, 0, 八度 * 21 + 8, 1, 2)efSpacer.lower()baSpacer = QtWidgets.QWidget()baSpacer.setMinimumWidth(25)layout.addWidget(baSpacer, 0, 八度 * 21 + 20, 1, 2)baSpacer.lower()# 最后一个 C 音符,最小宽度稍大八度 += 1lastButton = KeyButton((octaveStart + Octave) * 12)lastButton.setMinimumWidth(32)lastButton.triggered.connect(self.keyTriggered)layout.addWidget(lastButton, 0, 八度 * 21, 2, 3)# 将所有黑键放在其他所有东西之上对于 blackKeys 中的 keyButton:keyButton.raise_(​​)# 设置布局单元格的拉伸,如果在中间,则更大对于范围内的 col(layout.columnCount()):如果列 % 3 == 1:layout.setColumnStretch(col, 4)别的:layout.setColumnStretch(col, 3)self.setStyleSheet('''按键{颜色:rgb(50, 50, 50);边框:1px 起始 rgb(128, 128, 128);边界半径:2px;背景:白色;}按键:按下 {边框样式:插入;}KeyButton[isBlack=true] {颜色:RGB(250、250、250);背景:黑色;}KeyButton[isBlack=true]:按下 {背景:rgb(50, 50, 50);}''')def keyTriggered(self, key,pressed):八度,keyIdx = divmod(key, 12)keyName = '{}{}'.format(KeyNames[keyIdx],octave)state = 'pressed' 如果按下则为 'released'print('Key {} ({}) {}'.format(key, keyName, state))如果 __name__ == '__main__':导入系统app = QtWidgets.QApplication(sys.argv)键盘 = 键盘()键盘显示()sys.exit(app.exec_())

PS:我用几年前制作的键盘创建了一个要点.请注意,这段代码已经很旧了,当时我仍然有点缺乏经验(您可能需要更改 import 语句,因为它是针对 Qt.py 模块,允许 PyQt4/5 和 PySide 的透明集成):
https://gist.github.com/MaurizioB/43a053575f17eae7376e>6e6e

I am attempting to create a GUI keyboard. I am using QPushButton to replicate the keys. I am not focusing on linking it to MIDI yet. However, I was wondering if it is possible to create a Class using properties of QPushButton. By that I mean functions such as QPushButton.move/resize/setStyleSheet.

As it currently stands, my code is very long (Shown below). This is due to constant repetition of code to make each button. However, I have noticed that properties such as size, stylesheet and location (only on the y-axis) are the same, with the main difference being the x-axis and the y-axis between the black and white keys. If I were to make a class, how would I able to create objects with various properties?

Once again, if my logic is flawed or I have made any errors, please feel free to let me know.

import sys

from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QPushButton, QAction, QLineEdit, QMessageBox, QLabel \
    ,QDialog
from PyQt5.QtGui import QIcon, QHideEvent, QFont, QPixmap
from PyQt5.QtCore import pyqtSlot, QObject, QSize


class App(QMainWindow):

    def __init__(self):
        super().__init__()
        self.title = 'Piano '
        self.left = 620
        self.top =250
        self.width = 1920
        self.height = 1080
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.setFixedWidth(self.width)
        self.setFixedHeight(self.height)
        self.setStyleSheet("background-color:lightgrey")
        self.setWindowIcon(QIcon('img.png'))

        # Create a button in the window
        self.button1 = QPushButton('C', self)
        self.button1.move(10, 650)
        self.button1.setFont(QFont('Arial', 14))
        self.button1.resize(100,400)
        self.button1.setStyleSheet("background-color:white; border :1px solid ;") #Black Not Working

        self.button2 = QPushButton('D', self)
        self.button2.move(110,650)
        self.button2.setFont(QFont('Arial', 14))
        self.button2.resize(100, 400)
        self.button2.setStyleSheet("background-color:white; border :1px solid ;")

        self.button3 = QPushButton('E', self)
        self.button3.move(210, 650)
        self.button3.setFont(QFont('Arial', 14))
        self.button3.resize(100, 400)
        self.button3.setStyleSheet("background-color:white; border :1px solid ;")

        self.button4 = QPushButton('F', self)
        self.button4.move(310, 650)
        self.button4.setFont(QFont('Arial', 14))
        self.button4.resize(100, 400)
        self.button4.setStyleSheet("background-color:white; border :1px solid ;")

        self.button5 = QPushButton('G', self)
        self.button5.move(410, 650)
        self.button5.setFont(QFont('Arial', 14))
        self.button5.resize(100, 400)
        self.button5.setStyleSheet("background-color:white; border :1px solid ;")

        self.button6 = QPushButton('A', self)
        self.button6.move(510, 650)
        self.button6.setFont(QFont('Arial', 14))
        self.button6.resize(100, 400)
        self.button6.setStyleSheet("background-color:white; border :1px solid ;")

        self.button7 = QPushButton('B', self)
        self.button7.move(610, 650)
        self.button7.setFont(QFont('Arial', 14))
        self.button7.resize(100, 400)
        self.button7.setStyleSheet("background-color:white; border :1px solid ;")

        self.button8 = QPushButton('C2', self)
        self.button8.move(710, 650)
        self.button8.setFont(QFont('Arial', 14))
        self.button8.resize(100, 400)
        self.button8.setStyleSheet("background-color:white; border :1px solid ;")

        self.button2 = QPushButton('D2', self)
        self.button2.move(810, 650)
        self.button2.setFont(QFont('Arial', 14))
        self.button2.resize(100, 400)
        self.button2.setStyleSheet("background-color:white; border :1px solid ;")

        self.button3 = QPushButton('E2', self)
        self.button3.move(910, 650)
        self.button3.setFont(QFont('Arial', 14))
        self.button3.resize(100, 400)
        self.button3.setStyleSheet("background-color:white; border :1px solid ;")

        self.button4 = QPushButton('F2', self)
        self.button4.move(1010, 650)
        self.button4.setFont(QFont('Arial', 14))
        self.button4.resize(100, 400)
        self.button4.setStyleSheet("background-color:white; border :1px solid ;")

        self.button5 = QPushButton('G2', self)
        self.button5.move(1110, 650)
        self.button5.setFont(QFont('Arial', 14))
        self.button5.resize(100, 400)
        self.button5.setStyleSheet("background-color:white; border :1px solid ;")

        self.button6 = QPushButton('A2', self)
        self.button6.move(1210, 650)
        self.button6.setFont(QFont('Arial', 14))
        self.button6.resize(100, 400)
        self.button6.setStyleSheet("background-color:white; border :1px solid ;")

        self.button7 = QPushButton('B2', self)
        self.button7.move(1310, 650)
        self.button7.setFont(QFont('Arial', 14))
        self.button7.resize(100, 400)
        self.button7.setStyleSheet("background-color:white; border :1px solid ;")

        self.button8 = QPushButton('C3', self)
        self.button8.move(1410, 650)
        self.button8.setFont(QFont('Arial', 14))
        self.button8.resize(100, 400)
        self.button8.setStyleSheet("background-color:white; border :1px solid ;")

        self.button1up = QPushButton('C#', self)
        self.button1up.move(85, 650)
        self.button1up.setFont(QFont('Arial', 14))
        self.button1up.resize(50, 300)
        self.button1up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button2up = QPushButton('D#', self)
        self.button2up.move(185, 650)
        self.button2up.setFont(QFont('Arial', 14))
        self.button2up.resize(50, 300)
        self.button2up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button3up = QPushButton('F#', self)
        self.button3up.move(385, 650)
        self.button3up.setFont(QFont('Arial', 14))
        self.button3up.resize(50, 300)
        self.button3up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button4up = QPushButton('G#', self)
        self.button4up.move(485, 650)
        self.button4up.setFont(QFont('Arial', 14))
        self.button4up.resize(50, 300)
        self.button4up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button5up = QPushButton('A#', self)
        self.button5up.move(585, 650)
        self.button5up.setFont(QFont('Arial', 14))
        self.button5up.resize(50, 300)
        self.button5up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button6up = QPushButton(self)
        self.button6up.move(785, 650)
        self.button6up.setFont(QFont('Arial', 14))
        self.button6up.resize(50, 300)
        self.button6up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button7up = QPushButton(self)
        self.button7up.move(885, 650)
        self.button7up.setFont(QFont('Arial', 14))
        self.button7up.resize(50, 300)
        self.button7up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button8up = QPushButton(self)
        self.button8up.move(1085, 650)
        self.button8up.setFont(QFont('Arial', 14))
        self.button8up.resize(50, 300)
        self.button8up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button9up = QPushButton(self)
        self.button9up.move(1185, 650)
        self.button9up.setFont(QFont('Arial', 14))
        self.button9up.resize(50, 300)
        self.button9up.setStyleSheet("background-color:black; border :1px solid ;")

        self.button10up = QPushButton(self)
        self.button10up.move(1285, 650)
        self.button10up.setFont(QFont('Arial', 14))
        self.button10up.resize(50, 300)
        self.button10up.setStyleSheet("background-color:black; border :1px solid ;")

        # connect button to function on_click
        self.button1.clicked.connect(self.b1)

        self.show()

    @pyqtSlot()
    def b1(self):
       pass


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

解决方案

The first logic solution would be to create a list of data for each key, something like this:

KeyMap = (
    # key name, x, y, width, height, color
    ('C', 10, 650, 100, 400, 'white'),
    # ...
    ('C#', 85, 650, 50, 300, 'black'),
)

Then cycle through the list:

    baseStyle = 'background-color: {}; border :1px solid;'
    for key, x, y, width, height, color in KeyMap:
        button = QPushButton('key', self)
        button.setGeometry(x, y, width, height)
        button.setFont(QFont('Arial', 14))
        button.setStyleSheet(baseStyle.format(color)

Unfortunately, while the above might work fine for simple examples, I can tell you from experience that it won't work very well for this scenario (a piano-like keyboard), and mostly for these two reasons:

  • fixed geometries are rarely a good idea, if you need to resize the keyboard for any reason (including make it fit the screen, especially if its small) it will make everything much harder to code by hand;
  • you might need to extend the keyboard to more octaves or want to change the ratio between the widths and heights of keys;

I've had my share of experience on trying to create UI keyboards, and I ended up with a completely custom widget (based on a QGraphicsView), but for simple cases the following might suit your needs.

The trick is to use a Qt grid layout, which has the interesting "feature" of allowing items being overlapped if placed between its "cells".

The following code uses 2 rows (one for both white and black keys on top, one at the bottom for white keys) and 3 columns for each white key: while white keys use all three columns, black ones use the third column of the previous white key, and the first of the next; imagine a table like this:

+---+---+---+---+---+---+---+---+---+
|   ·   |   ·   |   |   ·   |   ·   |
|   ·   |   C   |   |   D   |   ·   |
|   ·   | sharp |   | sharp |   ·   |
|   ·   |   ·   |   |   ·   |   ·   |
+ · · · +---+---+ · +---+---+ · · · +
|   ·   ·   |   ·   ·   |   ·   ·   |
|   · C ·   |   · D ·   |   · E ·   |
|   ·   ·   |   ·   ·   |   ·   ·   |
+---+---+---+---+---+---+---+---+---+

Then you can create a basic class for the keys (including a signal for key triggering on press and release), and use simple lists to easily get if a key is white or black and place/style them accordingly.

The optional arguments are obviously for the octave range, and the octave start (since you're probably going to use MIDI, that's important, as you'll automatically get the key value).

from PyQt5 import QtCore, QtWidgets

BlackIdx = 1, 3, -1, 6, 8, 10
WhiteIdx = 0, 2, 4, 5, 7, 9, 11
KeyNames = 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'


class KeyButton(QtWidgets.QPushButton):
    triggered = QtCore.pyqtSignal(int, bool)
    def __init__(self, key, isBlack=False):
        super().__init__()
        self.key = key
        # this will be used by the stylesheet
        self.setProperty('isBlack', isBlack)

        octave, keyIdx = divmod(key, 12)
        self.setText('{}{}'.format(KeyNames[keyIdx], octave))

        self.setMinimumWidth(25)
        self.setMinimumSize(25, 80 if isBlack else 120)
        
        # ensure that the key expands vertically
        self.setSizePolicy(QtWidgets.QSizePolicy.Preferred, 
            QtWidgets.QSizePolicy.Expanding)

        # connect the pressed and released (not clicked!) signals to our custom one
        self.pressed.connect(lambda: self.triggered.emit(key, True))
        self.released.connect(lambda: self.triggered.emit(key, False))


class Keyboard(QtWidgets.QWidget):
    def __init__(self, octaves=2, octaveStart=3):
        super().__init__()
        layout = QtWidgets.QGridLayout(self)

        # the ratio between key heights: white keys are 1/3 longer than black ones
        layout.setRowStretch(0, 2)
        layout.setRowStretch(1, 1)
        layout.setSpacing(0)

        blackKeys = []
        for octave in range(octaves):
            for k in range(12):
                isBlack = k in BlackIdx
                keyButton = KeyButton(k + (octaveStart + octave) * 12, isBlack)
                keyButton.triggered.connect(self.keyTriggered)
                if isBlack:
                    keyPos = BlackIdx.index(k)
                    # column based on the index of the key list, plus 2 "cells"
                    col = keyPos * 3 + 2
                    # only one row in the layout
                    vSpan = 1
                    # only two columns
                    hSpan = 2
                    blackKeys.append(keyButton)
                else:
                    keyPos = WhiteIdx.index(k)
                    col = keyPos * 3
                    # two rows
                    vSpan = 2
                    # three columns
                    hSpan = 3
                col += octave * 21
                layout.addWidget(keyButton, 0, col, vSpan, hSpan)

            # "blank" spacers between E-F and B-C, to keep the spacings homogeneous
            efSpacer = QtWidgets.QWidget()
            efSpacer.setMinimumWidth(25)
            layout.addWidget(efSpacer, 0, octave * 21 + 8, 1, 2)
            efSpacer.lower()
            baSpacer = QtWidgets.QWidget()
            baSpacer.setMinimumWidth(25)
            layout.addWidget(baSpacer, 0, octave * 21 + 20, 1, 2)
            baSpacer.lower()

        # the last C note, with a minimum width a bit bigger
        octave += 1
        lastButton = KeyButton((octaveStart + octave) * 12)
        lastButton.setMinimumWidth(32)
        lastButton.triggered.connect(self.keyTriggered)
        layout.addWidget(lastButton, 0, octave * 21, 2, 3)

        # raise all black keys on top of everything else
        for keyButton in blackKeys:
            keyButton.raise_()

        # set the stretch of layout cells, if it's in the middle, it's bigger
        for col in range(layout.columnCount()):
            if col % 3 == 1:
                layout.setColumnStretch(col, 4)
            else:
                layout.setColumnStretch(col, 3)

        self.setStyleSheet('''
            KeyButton {
                color: rgb(50, 50, 50);
                border: 1px outset rgb(128, 128, 128);
                border-radius: 2px;
                background: white;
            }
            KeyButton:pressed {
                border-style: inset;
            }
            KeyButton[isBlack=true] {
                color: rgb(250, 250, 250);
                background: black;
            }
            KeyButton[isBlack=true]:pressed {
                background: rgb(50, 50, 50);
            }
        ''')

    def keyTriggered(self, key, pressed):
        octave, keyIdx = divmod(key, 12)
        keyName = '{}{}'.format(KeyNames[keyIdx], octave)
        state = 'pressed' if pressed else 'released'
        print('Key {} ({}) {}'.format(key, keyName, state))


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    keyboard = Keyboard()
    keyboard.show()
    sys.exit(app.exec_())

PS: I've created a gist with a keyboard I made some years ago. Do note that this code is quite old and I was still a bit unexperienced at the time (you might need to change the import statement, as it was aimed for the Qt.py module which allows transparent integration of PyQt4/5 and PySide):
https://gist.github.com/MaurizioB/43a053575f17eae371a9d7394e66a46e

这篇关于是否可以使用 PYQT5 中的元素创建一个类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆