class Example(QWidget): def __init__(self): super(QWidget, self).__init__() self.scrollBar = QScrollBar(Qt.Horizontal) self.scrollBar.valueChanged.connect(self.customSlot) self.messageBox = QMessageBox() self.messageBox.setIcon(QMessageBox.Information) self.messageBox.setWindowTitle('Информация') layout = QVBoxLayout() layout.addWidget(self.scrollBar) self.setLayout(layout) self.resize(300, 150) self.show() def customSlot(self, value): self.setWindowTitle(str(value)) if value == self.scrollBar.maximum(): self.messageBox.setInformativeText('Был достигнут максимум') self.messageBox.exec_() if value == self.scrollBar.minimum(): self.messageBox.setInformativeText('Был достигнут минимум') self.messageBox.exec_()
def bind(source: QScrollBar, target: QScrollBar) -> None: # bind target scroll bar to `source` (range and value). target.setRange(source.minimum(), source.maximum()) target.setValue(source.value()) source.rangeChanged.connect(target.setRange) source.valueChanged.connect(target.setValue)
class GraphViewer(QWidget): def __init__(self, parent): super().__init__(parent) self._y = 0 self._width = 1 self._height = 1 self.dot = Digraph(format='svg', strict=True) self._declared_count = 1 self._declared = dict() self._renderer = QSvgRenderer(self.dot.pipe(), self) self.scrollbar = QScrollBar(self.parent()) self.scrollbar.setRange(0, 0) self.parent().wheelEvent = self.wheelEvent def wheelEvent(self, event): if event.x() > self.getScrollWidth(): return if event.y() > self._height: return self.scrollbar.wheelEvent(event) def add(self, data): # is variable if data in self._declared.keys(): return self._declared[data] if data.is_variable: name = data.name self._declared[data] = name self.dot.node(name) if data.toward is not None: toward = self.add(data.toward) self.dot.edge(toward, name) return name # is constant if data.is_constant: name = data.symbol self._declared[data] = name self.dot.node(name) return name # is operator if data.is_operator: name = '[%d] %s' % (self._declared_count, data.name) self._declared_count += 1 self._declared[data] = name self.dot.node(name) args = [data.sub, data.obj, data.step] if data.args is not None: args += data.args args = [arg for arg in args if arg is not None] for arg in args: arg = self.add(arg) self.dot.edge(arg, name) return name def paintEvent(self, event): self._width = self.width() self._height = self.height() self.scrollbar.setGeometry(self.getScrollWidth(), 0, 20, self._height) self.resize(self._renderer.defaultSize()) painter = QPainter(self) painter.restore() drawRect = QRectF(self.rect()) if self.scrollbar.maximum() == 0: draw_y = 0 else: draw_y = drawRect.height() - self._height draw_y *= self.scrollbar.value() / self.scrollbar.maximum() drawRect.setY(-draw_y) drawRect.setHeight(drawRect.y() + drawRect.height()) self._renderer.render(painter, drawRect) def flush(self): self._renderer = QSvgRenderer(self.dot.pipe()) max_h = self._renderer.defaultSize().height() / self._height if max_h <= 1: max_h = 0 max_h = int(self.delta() * max_h) self.scrollbar.setMaximum(max_h) def clear(self): self._declared_count = 1 self._declared = dict() self.dot.clear() def getScrollWidth(self): return self._width - 20 def delta(self): return 3.14
class TextArea(QWidget): """ 自定义文本展示区域(PS:不能键盘输入那种) 功能:能自动拉长文本区域并且带有滑动条 """ def __init__(self, parent): super().__init__(parent) self.setContentsMargins(0, 0, 0, 0) # 滚动条的宽度 # 对于水平方向的滚动条其实是高度 self.scrollBarWidth = 15 # 文本区 self.textContainer = TextView(self) self.textContainer.setContentsMargins(5, 0, 0, 0) # 设置居顶部显示 self.textContainer.setAlignment(Qt.AlignTop) # 设置文本区域根据文本进行自适应 self.textContainer.adjustSize() self.textContainer.setCallback(self.sizeChange) # 垂直滚动条 self.vBar = QScrollBar(Qt.Vertical, self) # self.vBar.sliderMoved.connect(self.dragV) self.vBar.valueChanged.connect(self.changeVertical) # 一开始隐藏 self.vBar.setVisible(False) # 在水平方向上文字的总长度是否超过容器的宽度标志位 # 只要出现一次超过,那么 self.overHorizontal就永远是True # 除非将超过容器宽度的文本都去除 self.overHorizontal = False # 水平方向上滑块上一次的值 self.hPreValue = 0 # 水平滚动条 self.hBar = QScrollBar(Qt.Horizontal, self) # self.hBar.sliderMoved.connect(self.dragH) self.hBar.valueChanged.connect(self.changeHorizontal) # 初始化的时候隐藏自身 self.hBar.setVisible(False) # 在垂直方向上文字的总高度是否超过容器的高度标志位 # 只要出现一次超过,那么 self.overVertical就永远是True # 除非将超过容器高度的文本都去除 self.overVertical = False # 垂直方向上滑块上一次的值 self.vPreValue = 0 def setSize(self, width, height): """ 设置TextArea的宽度和高度 :param width: 宽度 :param height: 高度 :return: no return """ self.resize(width, height) self.setMaximumSize(width, height) self.setMinimumSize(width, height) # 设置垂直方向ScrollBar的宽度和高度 # 垂直方向ScrollBar的高度等于TextArea的高度 self.vBar.resize(self.scrollBarWidth, height - self.scrollBarWidth) # 移动到指定位置 self.vBar.move(width - self.scrollBarWidth, 0) # 设置水平方向的ScrollBar的宽度和高度 # 水平方向ScrollBar的高度为self.scrollBarWidth self.hBar.resize(width, self.scrollBarWidth) self.hBar.move(0, height - self.scrollBarWidth) # 设置文本区域的高度和宽度 self.textContainer.resize(width, height) self.setStyleSheet("background-color: #088A68;") self.textContainer.setStyleSheet("border: 1px solid #FF0000; color: #FFFFFF;") def setMaximumSize(self, maxw: int, maxh: int) -> None: super().setMaximumSize(maxw, maxh) def setClassName(self, textAreaName=None, labelName=None, vBarName=None, hBarName=None): """ 设置ObjectName :param textAreaName: TextArea的ObjectName :param labelName: 文本区域的ObjectName :param vBarName: 垂直ScrollBar的ObjectName :param hBarName: 水平ScrollBar的ObjectName :return: """ self.setObjectName(textAreaName) self.textContainer.setObjectName(labelName) self.hBar.setObjectName(hBarName) self.vBar.setObjectName(vBarName) def append(self, text): self.textContainer.adjustSize() self.textContainer.append(text) margin = self.contentsMargins() # 如果文本长度超过了容器的宽度, 将标准位置为True # 并且显示水平滑动条 if self.textContainer.width() > (self.width() - margin.left() - margin.right()): self.overHorizontal = True self.hBar.setVisible(True) # 如果文本总高度度超过了容器的宽度, 将标准位置为True # 并且显示垂直滑动条 if self.textContainer.height() > (self.height() - margin.top() - margin.bottom()): self.overVertical = True self.vBar.setVisible(True) def dragHortizontal(self, value): """ 滑块水平方向上的拖拽事件 :argument value :return: """ print("H: " + str(value)) def dragVertical(self, value): """ 滑块垂直方向上的拖拽事件 :argument value :return: """ print("V: " + str(value)) def changeHorizontal(self, v): """ 垂直滑块的值发生改变时 :param v: :return: """ if v == 0: # 由于下列的操作会产生浮点型数据,所以在计算坐标的时候总有偏差 # 所以在 v = 0, 也就是滑动条回到最开始的地方, # self.textContainer对应方向上的坐标也归0,那样就不会出问题了 self.textContainer.move(0, self.textContainer.y()) # 将当前值作为下一次的preValue self.hPreValue = v return # print("change H: {}".format(v)) textW = self.textContainer.width() # 最大值(从0开始计算) maximum = self.hBar.maximum() + 1 # 计算每次改变值对应 self.textContainer在水平方向上需要移动的尺寸 stepW = textW / maximum # 当前值与上一次的值得差 change = v - self.hPreValue move = int(self.textContainer.x() - stepW * change) self.textContainer.move(move, self.textContainer.y()) # 将当前值作为下一次的preValue self.hPreValue = v def changeVertical(self, v): """ 水平滑块的值发生改变时 :param v: :return: """ if v == 0: # 由于下列的操作会产生浮点型数据,所以在计算坐标的时候总有偏差 # 所以在 v = 0, 也就是滑动条回到最开始的地方, # self.textContainer对应方向上的坐标也归0,那样就不会出问题了 self.textContainer.move(self.textContainer.x(), 0) self.vPreValue = v return # print("change V: {}".format(v)) textH = self.textContainer.width() # 最大值(从0开始计算) maximum = self.vBar.maximum() - self.vBar.minimum() + self.vBar.pageStep() # 计算每次改变值对应 self.textContainer在水平方向上需要移动的尺寸 stepH = float(textH) / maximum # 当前值与上一次的值得差 change = v - self.vPreValue move = int(self.textContainer.y() - stepH * change) self.textContainer.move(self.textContainer.x(), move) # 将当前值作为下一次的preValue self.vPreValue = v def sizeChange(self, obj: QLabel): print("size change:{},{} ".format(obj.width(), obj.height()))
def __init__(self, server): super().__init__() self.exit_condition = exit_condition self.server = server self.timer = QTimer() self.timer.timeout.connect(self.show_message) self.timer.start(500) self.setWindowIcon(QIcon(os.path.join('pictures', 'raven.jpg'))) self.setWindowTitle("RavenChat") # creating main labels self.user_host = QLabel( 'Your host: ({}, {})'.format(self.server.server_ip, self.server.server_port), self) self.user_name = QLabel("Your name: {}".format(self.server.name), self) self.online_label = QLabel("Users online", self) # creating scroll bar qsb = QScrollBar() qsb.setTracking(False) qsb.setSliderPosition(qsb.maximum()) # creating window to show users online self.users_online = QTextEdit() self.users_online.setReadOnly(True) self.users_online.setHorizontalScrollBar(qsb) self.users_online.setMaximumWidth(200) self.users_online.setMinimumWidth(170) # creating window to show chat messages self.chat_window = QTextEdit() self.chat_window.setReadOnly(True) self.chat_window.setHorizontalScrollBar(qsb) # creating button to send messages self.sending_button = QPushButton(self) self.sending_button.setIcon( QIcon(os.path.join('pictures', 'feather.png'))) self.sending_button.setMaximumSize(100, 50) self.sending_button.clicked.connect(self.send_message) # creating menu self.create_connection_action = QAction("Create connection") self.create_connection_action.triggered.connect(self.create_connection) self.change_name_action = QAction("Change name") self.change_name_action.triggered.connect(self.change_name) bar = self.menuBar() self.bar = bar.addMenu('Settings') self.bar.addAction(self.create_connection_action) self.bar.addAction(self.change_name_action) # creating line to write messages self.send_line = QLineEdit() # creating button to send files self.file_sending_button = QPushButton(self) self.file_sending_button.setIcon( QIcon(os.path.join('pictures', 'file.png'))) self.file_sending_button.setMaximumSize(70, 50) self.file_sending_button.clicked.connect(self.offer_file) self.main_widget = QWidget() self.main_widget.grid = QGridLayout() # adding labels, windows and buttons in grid self.main_widget.grid.addWidget(self.user_host, 1, 1, 1, 2) self.main_widget.grid.addWidget(self.user_name, 2, 1, 1, 2) self.main_widget.grid.addWidget(self.online_label, 3, 1, 1, 2) self.main_widget.grid.addWidget(self.users_online, 4, 1, 1, 2) self.main_widget.grid.addWidget(self.chat_window, 1, 3, 4, 1) self.main_widget.grid.addWidget(self.send_line, 5, 3) self.main_widget.grid.addWidget(self.sending_button, 5, 2) self.main_widget.grid.addWidget(self.file_sending_button, 5, 1) self.main_widget.setLayout(self.main_widget.grid) self.setCentralWidget(self.main_widget) self.main_widget.setGeometry(300, 300, 300, 300) self.update_online_connections() self.create_downloads_folder()