Skip to content

Commit

Permalink
add pyqt6 docs
Browse files Browse the repository at this point in the history
  • Loading branch information
make46 committed Dec 17, 2021
1 parent 82e2787 commit c0e5283
Show file tree
Hide file tree
Showing 122 changed files with 10,670 additions and 18 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License

Copyright (c) 2015-2020 maicss github.com/maicss
Copyright (c) 2015-2021 maicss https://github.com/maicss

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
# 前言
# 项目介绍
翻译自 zetcode 的 PyQt 教程。

PyQt5中文教程,翻译自 [zetcode](http://zetcode.com/gui/pyqt5/)GitBook 预览地址:[https://maicss.gitbook.io/pyqt5-chinese-tutoral/](https://maicss.gitbook.io/pyqt5-chinese-tutoral/)
GitBook 预览地址:[https://maicss.gitbook.io/pyqt-chinese-tutoral/](https://maicss.gitbook.io/pyqt-chinese-tutoral/)

这个教程比较好的地方是,能讲解每一段代码的含义
开始阅读 [PyQt5](./pyqt5/index.md) 教程

虽然PyQt的函数命名已经非常语义化了,但是对于新手来说,有这一步还是更好的
开始阅读 [PyQt6](./pyqt6/index.md) 教程

所以我选择了翻译这篇教程,希望能给刚入门的你带来帮助。
## 前言

翻译的水平有限\(如有错误,请指出\),而且有些地方是自己的理解,也加入了自己的提示在里面(并没有标注出来),所以并不完全等于原文。

我尽量让翻译不带英语腔,做到即使一个完全不懂编程的人来看,虽然不知道说的啥,但是最起码语句通顺,不会读着别扭。也算是对老师的一点敬意吧~~
这个教程比较好的地方是,能讲解每一段代码的含义。虽然PyQt的函数命名已经非常语义化了,但是对于新手来说,有这一步还是更好的。希望这篇能给刚入门的你带来帮助。

## 翻译吐槽:
翻译的水平有限\(如有错误,请指出\),而且有些地方是自己的理解,也加入了自己的提示在里面(并没有标注出来),所以并不完全等于原文。

* label 这个词好难翻译,有时候就是个占位符的意思,说是文字说明吧,有专门的词 caption,但是像 checkbox 的名称这种的,不是文字说明又是啥...,但是居然还用 label 说图标这种事情,也是醉了。
* 源文档更新了,但是没有更新日志,只能一段段的比对……长了记性,创建了一个源文档的文件,下次直接 copy 的时候用 VCS 对比就可以了。
* 更新了一些图片,主要是原来没有的。因为手头没有Windows,而且源文档的图片也是不是Windows10,都不是一个风格的,凑合着看吧……
我尽量让翻译不带英语腔,做到即使一个完全不懂编程的人来看,虽然不知道说的啥,但是最起码语句通顺,不会读着别扭。

## 更新:
添加了一些原文没有带的图片。所以有的图片风格跟原文的不一样。

### 2017-8
## 更新日志:

### 2017-08
* [原文地址](https://zetcode.com/gui/pyqt5/)
* 菜单和工具栏 【新增】 右键菜单 子菜单 勾选菜单
* 事件和信号 【新增】 事件对象
* 绘图 【新增】 贝塞尔曲线

### 2021-12

* 新增 PyQt6 教程,原文地址:[Python PyQt6](https://zetcode.com/pyqt6/)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
224 changes: 224 additions & 0 deletions original/pyqt6/customwidgets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
# Custom widgets in PyQt6
*last modified May 17, 2021*

PyQt6 has a rich set of widgets. However, no toolkit can provide all widgets that programmers might need in their applications. Toolkits usually provide only the most common widgets like buttons, text widgets, or sliders. If there is a need for a more specialised widget, we must create it ourselves.

Custom widgets are created by using the drawing tools provided by the toolkit. There are two basic possibilities: a programmer can modify or enhance an existing widget or he can create a custom widget from scratch.

## PyQt6 burning widget
This is a widget that we can see in Nero, K3B, or other CD/DVD burning software.

``` python
# file: burning_widget.py
#!/usr/bin/python

"""
ZetCode PyQt6 tutorial
In this example, we create a custom widget.
Author: Jan Bodnar
Website: zetcode.com
"""

from PyQt6.QtWidgets import (QWidget, QSlider, QApplication,
QHBoxLayout, QVBoxLayout)
from PyQt6.QtCore import QObject, Qt, pyqtSignal
from PyQt6.QtGui import QPainter, QFont, QColor, QPen
import sys


class Communicate(QObject):
updateBW = pyqtSignal(int)


class BurningWidget(QWidget):

def __init__(self):
super().__init__()

self.initUI()


def initUI(self):

self.setMinimumSize(1, 30)
self.value = 75
self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]


def setValue(self, value):

self.value = value


def paintEvent(self, e):

qp = QPainter()
qp.begin(self)
self.drawWidget(qp)
qp.end()


def drawWidget(self, qp):

MAX_CAPACITY = 700
OVER_CAPACITY = 750

font = QFont('Serif', 7, QFont.Weight.Light)
qp.setFont(font)

size = self.size()
w = size.width()
h = size.height()

step = int(round(w / 10))

till = int(((w / OVER_CAPACITY) * self.value))
full = int(((w / OVER_CAPACITY) * MAX_CAPACITY))

if self.value >= MAX_CAPACITY:

qp.setPen(QColor(255, 255, 255))
qp.setBrush(QColor(255, 255, 184))
qp.drawRect(0, 0, full, h)
qp.setPen(QColor(255, 175, 175))
qp.setBrush(QColor(255, 175, 175))
qp.drawRect(full, 0, till - full, h)

else:

qp.setPen(QColor(255, 255, 255))
qp.setBrush(QColor(255, 255, 184))
qp.drawRect(0, 0, till, h)

pen = QPen(QColor(20, 20, 20), 1,
Qt.PenStyle.SolidLine)

qp.setPen(pen)
qp.setBrush(Qt.BrushStyle.NoBrush)
qp.drawRect(0, 0, w - 1, h - 1)

j = 0

for i in range(step, 10 * step, step):

qp.drawLine(i, 0, i, 5)
metrics = qp.fontMetrics()
fw = metrics.horizontalAdvance(str(self.num[j]))

x, y = int(i - fw/2), int(h / 2)
qp.drawText(x, y, str(self.num[j]))
j = j + 1


class Example(QWidget):

def __init__(self):
super().__init__()

self.initUI()


def initUI(self):

OVER_CAPACITY = 750

sld = QSlider(Qt.Orientations.Horizontal, self)
sld.setFocusPolicy(Qt.FocusPolicy.NoFocus)
sld.setRange(1, OVER_CAPACITY)
sld.setValue(75)
sld.setGeometry(30, 40, 150, 30)

self.c = Communicate()
self.wid = BurningWidget()
self.c.updateBW[int].connect(self.wid.setValue)

sld.valueChanged[int].connect(self.changeValue)
hbox = QHBoxLayout()
hbox.addWidget(self.wid)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)

self.setGeometry(300, 300, 390, 210)
self.setWindowTitle('Burning widget')
self.show()


def changeValue(self, value):

self.c.updateBW.emit(value)
self.wid.repaint()


def main():

app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec())


if __name__ == '__main__':
main()
```
In our example, we have a `QSlider` and a custom widget. The slider controls the custom widget. This widget shows graphically the total capacity of a medium and the free space available to us. The minimum value of our custom widget is 1, the maximum is OVER_CAPACITY. If we reach value MAX_CAPACITY, we begin drawing in red colour. This normally indicates overburning.

The burning widget is placed at the bottom of the window. This is achieved using one `QHBoxLayout` and one `QVBoxLayout`.

```python
class BurningWidget(QWidget):

def __init__(self):
super().__init__()
```
The burning widget it based on the `QWidget` widget.

```python
self.setMinimumSize(1, 30)
```
We change the minimum size (height) of the widget. The default value is a bit small for us.
```python
font = QFont('Serif', 7, QFont.Weight.Light)
qp.setFont(font)
```
We use a smaller font than the default one. This better suits our needs.

```python
size = self.size()
w = size.width()
h = size.height()

step = int(round(w / 10))


till = int(((w / OVER_CAPACITY) * self.value))
full = int(((w / OVER_CAPACITY) * MAX_CAPACITY))
```
We draw the widget dynamically. The greater is the window, the greater is the burning widget and vice versa. That is why we must calculate the size of the widget onto which we draw the custom widget. The till parameter determines the total size to be drawn. This value comes from the slider widget. It is a proportion of the whole area. The full parameter determines the point where we begin to draw in red colour.

The actual drawing consists of three steps. We draw the yellow or the red and yellow rectangle. Then we draw the vertical lines which divide the widget into several parts. Finally, we draw the numbers which indicate the capacity of the medium.

``` python
metrics = qp.fontMetrics()
fw = metrics.horizontalAdvance(str(self.num[j]))

x, y = int(i - fw/2), int(h / 2)
qp.drawText(x, y, str(self.num[j]))
```
We use font metrics to draw the text. We must know the width of the text in order to center it around the vertical line.

``` python
def changeValue(self, value):

self.c.updateBW.emit(value)
self.wid.repaint()
```
When we move the slider, the changeValue method is called. Inside the method, we send a custom updateBW signal with a parameter. The parameter is the current value of the slider. The value is later used to calculate the capacity of the Burning widget to be drawn. The custom widget is then repainted.

![The burning widget](./images/burning.png)

Figure: The burning widget

In this part of the PyQt6 tutorial, we created a custom widget.
Loading

0 comments on commit c0e5283

Please sign in to comment.