MyModHeaven 发表于 2023-3-30 10:09

pyside/pyqt,图片左上角显示标题的字体颜色问题

本帖最后由 MyModHeaven 于 2023-3-30 10:13 编辑

[!(https://www.helloimg.com/images/2023/03/30/o3W97C.md.png)](https://www.helloimg.com/image/o3W97C)

如图,当鼠标进入tablewidgetitem时,图片的标题会显示出来。标题文本的颜色,通过CalculateTextColor类计算出来(图片平均颜色的对比色)。但是我发现,计算的时间有点长,六七秒才会变颜色,而且期间CPU的占用很大,达到百分之四五十。
耗费时间长和资源占用多的问题该怎么解决?
如果不计算对比色,可以设置一下标题的背景颜色,这样虽然一劳永逸,但是总感觉标题和图片的界限太明显,影响观感。除此之外,有没有其他的方案,避免字体颜色和壁纸颜色相近?

以下是代码:
```
import sys
from os import chdir, path
from time import sleep

import requests
from PySide6.QtWidgets import QSizePolicy, QVBoxLayout, QWidget, QHBoxLayout, QToolTip, QPushButton, QLabel, QTableWidget,\
                              QApplication, QAbstractItemView, QDialog
from PySide6.QtGui import QIcon, QPixmap, QColor
from PySide6.QtCore import Qt, QThread, Signal

filepath = path.abspath(__file__)
chdir(path.dirname(filepath))


class Ui_Form(QWidget):
    blankRow = 0
    blankColumn = 0

    def __init__(self, rule):
      super().__init__()
      self.rule = rule
      self.setupUi(self, rule)
      self.show()

    def setupUi(self, Form, rule):
      # 窗体基本设置
      Form.resize(1300, 700)
      Form.setWindowTitle(rule['name'])
      self.setWindowFlags(Qt.FramelessWindowHint)      # 去掉窗口标题栏
      self.setMouseTracking(True)   # 跟踪鼠标移动
      mainLayout = QVBoxLayout(Form)
      mainLayout.setContentsMargins(0, 0, 0, 0)

      # 标题栏
      self.logoLabel = QLabel()
      self.logoLabel.setFixedSize(30, 30)
      self.I = Img(rule['logoUrl'])
      self.I.imgSin.connect(self.setLogo)
      self.I.start()
      titleLabel = QLabel(objectName='titleLabel')
      titleLabel.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
      titleLabel.setText(rule['name'])
      titleBar = QWidget(objectName='titleBar')
      titleBar.setMaximumHeight(40)
      mainLayout.addWidget(titleBar)
      titleBarLayout = QHBoxLayout(titleBar, spacing=0)
      titleBarLayout.setContentsMargins(0, 0, 0, 0)
      self.copyurlButton = QPushButton(clicked=self.copyUrl, objectName='copyurlButton')
      self.copyurlButton.setFixedSize(40, 30)
      self.copyurlButton.setIcon(QIcon(QPixmap('./img/url.png')))
      self.copyurlButton.setToolTip('复制网址')
      minimizeButton = QPushButton(clicked=self.showMinimized, objectName='minimizeButton')
      minimizeButton.setFixedSize(40, 30)
      minimizeButton.setIcon(QIcon(QPixmap('./img/minimize.png')))
      self.maximizeButton = QPushButton(clicked=self.maximized, objectName='maximizeButton')       # 需要实现两个功能:最大化和恢复正常,所以自定义 self.maximized()
      self.maximizeButton.setFixedSize(40, 30)
      self.maximizeButton.setIcon(QIcon(QPixmap('./img/maximize.png')))
      closeButton = QPushButton(clicked=self.close, objectName='closeButton')
      closeButton.setFixedSize(40, 30)
      closeButton.setIcon(QIcon(QPixmap('./img/close.png')))
      titleBarLayout.addWidget(self.logoLabel)
      titleBarLayout.addSpacing(10)   # 设置 logo 和 title 的间隔
      titleBarLayout.addWidget(titleLabel, alignment=Qt.AlignLeft)
      titleBarLayout.addWidget(self.copyurlButton)
      titleBarLayout.addWidget(minimizeButton)
      titleBarLayout.addWidget(self.maximizeButton)
      titleBarLayout.addWidget(closeButton)


      imgUrl = '      http://img.netbian.com/file/2023/0305/small180944SteRA1678010984.jpg'
      imgTitle = '白色衣服长发古风古装美女动漫壁纸'

      # 内容区
      self.picTable = QTableWidget(8, 3)
      self.picTable.setShowGrid(False)      # 隐藏网格线
      self.picTable.setMinimumSize(1250, 600)   # 设置最小尺寸
      self.picTable.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)   # 设置垂直滚动条像素级滚动
      self.picTable.setEditTriggers(QAbstractItemView.NoEditTriggers)   # 禁止编辑
      self.picTable.setSelectionMode(QAbstractItemView.ContiguousSelection)   # 设置选择模式
      horizontalHeader = self.picTable.horizontalHeader()
      horizontalHeader.setVisible(False)       # 隐藏水平表头
      horizontalHeader.setDefaultSectionSize(410)   # 设置列宽
      verticalHeader = self.picTable.verticalHeader()
      verticalHeader.setVisible(False)         # 隐藏垂直表头
      verticalHeader.setDefaultSectionSize(235)       # 设置行高

      mainLayout.addWidget(self.picTable, alignment=Qt.AlignHCenter)


      for i in range(6):
            imgLabel = ImgCell(imgTitle, imgUrl)
            self.picTable.setCellWidget(self.blankRow, self.blankColumn, imgLabel)
            self.calculatePos()   # 更新空白单元格的位置

      

    def copyUrl(self):
      app = QApplication.instance()
      app.clipboard().setText(self.rule['baseUrl'])
      self.copyurlButton.setIcon(QIcon(QPixmap('./img/copied.png')))
      self.C = Copy()
      self.C.copySin.connect(lambda: self.copyurlButton.setIcon(QIcon(QPixmap('./img/url.png'))))
      self.C.start()
      QToolTip.showText(self.cursor().pos(), '复制成功')
      
    def maximized(self):
      # 窗口最大化和恢复正常
      if self.isMaximized():
            self.showNormal()
            self.maximizeButton.setIcon(QIcon(QPixmap('./img/maximize.png')))
      else:
            self.showMaximized()
            self.maximizeButton.setIcon(QIcon(QPixmap('./img/normal.png')))
   

   
    def setLogo(self, sin):
      if isinstance(sin, bytes):
            logo = QPixmap()
            logo.loadFromData(sin)
            self.logoLabel.setPixmap(logo)
      else:
            pass
   
    def calculatePos(self):
      # 计算空白的位置
      if self.blankColumn < 2:
            self.blankColumn += 1
      else:
            self.blankRow += 1
            self.blankColumn = 0



class Copy(QThread):
    copySin = Signal(bool)

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

    def run(self):
      sleep(2)
      self.copySin.emit(True)


class Img(QThread):
    imgSin = Signal(object)

    def __init__(self, imgUrl):
      super().__init__()
      self.imgUrl = imgUrl
   
    def run(self):
      while True:
            try:
                imgContent = requests.get(self.imgUrl, headers={'user-agent': 'Chrome/110.0.0.0'}).content
                self.imgSin.emit(imgContent)
                break
            except:
                self.imgSin.emit(False)

class ImgCell(QLabel):
    def __init__(self, imgTitle, imgUrl):
      super().__init__()
      self.imgTitle = imgTitle
      self.imgUrl = imgUrl
      self.setupUi()

    def setupUi(self):
      self.setFixedSize(400, 225)
      self.setScaledContents(True)
      
      self.I = Img(self.imgUrl)
      self.I.imgSin.connect(self.setImg)
      self.I.start()
      self.titleLabel = QLabel()
      self.titleLabel.setWordWrap(True)    # 允许换行显示
      self.titleLabel.setText(self.imgTitle)
      self.titleLabel.hide()
      self.bigButton = QPushButton(clicked=self.bigImg)
      self.bigButton.setFixedSize(20, 20)
      self.bigButton.setStyleSheet('background-color: rgba(255, 255, 255, 128); border-radius: 5px')   # 设置透明度和圆角
      self.bigButton.setIcon(QIcon(QPixmap('./img/big.png')))
      self.bigButton.setToolTip('放大')
      self.bigButton.hide()
      self.dlButton = QPushButton()
      self.dlButton.setFixedSize(20, 20)
      self.dlButton.setStyleSheet('background-color: rgba(255, 255, 255, 128); border-radius: 5px')
      self.dlButton.setIcon(QIcon(QPixmap('./img/download.png')))
      self.dlButton.setToolTip('下载')
      self.dlButton.hide()
      self.copyurlButton = QPushButton(clicked=self.copyUrl, objectName='copyurlButton')
      self.copyurlButton.setFixedSize(20, 20)
      self.copyurlButton.setStyleSheet('background-color: rgba(255, 255, 255, 128); border-radius: 5px')
      self.copyurlButton.setIcon(QIcon(QPixmap('./img/url.png')))
      self.copyurlButton.setToolTip('复制网址')
      self.copyurlButton.hide()
      buttonLayout = QHBoxLayout()
      buttonLayout.addWidget(self.bigButton)
      buttonLayout.addWidget(self.dlButton)
      buttonLayout.addWidget(self.copyurlButton)
      buttonLayout.setSpacing(5)
      layout = QVBoxLayout(self)
      layout.addWidget(self.titleLabel, alignment=Qt.AlignTop)
      layout.addLayout(buttonLayout)
      layout.setAlignment(buttonLayout, Qt.AlignRight | Qt.AlignBottom)

    def copyUrl(self):
      app = QApplication.instance()
      app.clipboard().setText(self.imgUrl)
      self.copyurlButton.setIcon(QIcon(QPixmap('./img/copied.png')))
      self.copyurlButton.setEnabled(False)
      self.C = Copy()
      self.C.copySin.connect(self.copied)
      self.C.start()
      QToolTip.showText(self.cursor().pos(), '复制成功')
   
    def copied(self):
      # 复制结束后
      self.copyurlButton.setIcon(QIcon(QPixmap('./img/url.png')))
      self.copyurlButton.setEnabled(True)

    def setImg(self, img):
      self.img = img
      imgPixmap = QPixmap()
      imgPixmap.loadFromData(img)
      self.setPixmap(imgPixmap)
      self.CTC = CalculateTextColor(img)
      self.CTC.colorSin.connect(lambda color: self.titleLabel.setStyleSheet(f'color: {color}'))
      self.CTC.start()

    def enterEvent(self, event):
      self.titleLabel.show()
      self.bigButton.show()
      self.dlButton.show()
      self.copyurlButton.show()

    def leaveEvent(self, event):
      self.titleLabel.hide()
      self.bigButton.hide()
      self.dlButton.hide()
      self.copyurlButton.hide()
   
    def bigImg(self):
      self.BI = BigImg(self.img)


class CalculateTextColor(QThread):
    # 计算图片的对比色
    colorSin = Signal(str)

    def __init__(self, pixmap):
      super().__init__()
      self.pixmapData = pixmap

    def run(self):
      # 计算图片的平均颜色
      pixmap = QPixmap()
      pixmap.loadFromData(self.pixmapData)
      img = pixmap.toImage()
      width, height= img.width(), img.height()
      red = green = blue = 0
      for x in range(width):
            for y in range(height):
                pixel = QColor(img.pixel(x, y))
                red += pixel.red()
                green += pixel.green()
                blue ++ pixel.blue()
      totalPixels = width * height
      avgColor = QColor(red//totalPixels, green//totalPixels, blue//totalPixels)
      color = avgColor.lighter().name()       # 计算对比色
      self.colorSin.emit(color)

class BigImg(QDialog):
    # 完全显示缩略图
    # bigimgSin = Signal

    def __init__(self, pixmap):
      super().__init__()
      self.setupUi(pixmap)

    def setupUi(self, img):
      imgLabel = QLabel(self)
      pixmap = QPixmap()
      pixmap.loadFromData(img)
      imgLabel.setPixmap(pixmap)
      imgLabel.adjustSize()
      self.show()
   
    def leaveEvent(self, event):
      self.close()



if __name__ == '__main__':
    styleSheet = '''
    #titleBar {
    background-color: #bdbdbd
    }
    #titleLabel {
    font-family: 小米兰亭;
    font-size: 20px
    }
    /*复制网址、最小化、最大化、关闭按钮通用默认背景*/
    #copyurlButton, #minimizeButton, #maximizeButton, #closeButton {
    border: 0;
    }
    /*悬停*/
    #copyurlButton, #minimizeButton:hover, #maximizeButton:hover {
    background-color: #a6a6a6
    }
    #closeButton:hover {
    background-color: red
    }
    QTableWidget {
    border: 0;
    background-color: #f0f0f0
    }
    /*设置单元格的内容边距*/
    QTableWidget::item {
    padding: 5
    }
    /*图片弄成圆角比较麻烦,先不搞了*/
    QLabel {
    border: 2px;
    }
    '''
    app = QApplication(sys.argv)
    app.setStyleSheet(styleSheet)
    rule = {'name': '彼岸桌面', 'baseUrl': 'http://www.netbian.com', "logoUrl": "http://www.netbian.com/favicon.ico"}
    ui = Ui_Form(rule)                  # 创建 PyQt 设计的窗体对象
    sys.exit(app.exec())                   # 程序关闭时退出进程
```

~零度 发表于 2023-3-30 10:36

本帖最后由 ~零度 于 2023-3-30 10:42 编辑

你只计算你要放置标题文字区域内图片像素的对比色就行了呀,而且也不用完全遍历所有像素点吧,比如说每一行像素每5个像素里边只统计第一个像素,图片里面有大量重复的像素,这样子做和原来的方式不会有很大差别


比如这样子改一下,计算量就减小到原来的16分之一

for x in range(0, width, 4): #四分之一下采样
            for y in range(0, height, 4): #四分之一下采样
                pixel = QColor(img.pixel(x, y))
                red += pixel.red()
                green += pixel.green()
                blue ++ pixel.blue()

Arcticlyc 发表于 2023-3-30 11:13

请问下楼主,pyside设计是自己写代码还是用designer生成啊,有没有啥教程哇{:1_923:}

MyModHeaven 发表于 2023-3-30 14:11

Arcticlyc 发表于 2023-3-30 11:13
请问下楼主,pyside设计是自己写代码还是用designer生成啊,有没有啥教程哇

怎么弄都行,个人习惯。刚开始我还用designer,后来嫌麻烦,直接从第一行自己写。教程,要不找本书,要不在b站找个视频

Arcticlyc 发表于 2023-3-30 14:30

MyModHeaven 发表于 2023-3-30 14:11
怎么弄都行,个人习惯。刚开始我还用designer,后来嫌麻烦,直接从第一行自己写。教程,要不找本书,要不 ...

好的,谢谢

MyModHeaven 发表于 2023-3-30 14:44

~零度 发表于 2023-3-30 10:36
你只计算你要放置标题文字区域内图片像素的对比色就行了呀,而且也不用完全遍历所有像素点吧,比如说每一行 ...

确实,我竟然没想到,多谢
页: [1]
查看完整版本: pyside/pyqt,图片左上角显示标题的字体颜色问题