新增联系人头像组件

This commit is contained in:
shuaikangzhou 2023-11-15 21:57:29 +08:00
parent 37870f1033
commit 07b20a2f21
11 changed files with 677 additions and 90 deletions

View File

@ -4,25 +4,17 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="修复无法查找wxid的bug">
<change afterPath="$PROJECT_DIR$/app/ui_pc/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/ui_pc/tool/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/ui_pc/tool/toolUI.ui" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/ui_pc/tool/tool_window.py" afterDir="false" />
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="修改UI">
<change afterPath="$PROJECT_DIR$/app/components/CAvatar.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/components/contact_info_ui.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/ui_pc/contact/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/ui_pc/contact/contact_window.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/MyComponents/Button_Contact.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/components/Button_Contact.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/MyComponents/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/components/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/MyComponents/prompt_bar.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/components/prompt_bar.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/Ui/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/chat/chat.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/Ui/chat/chat.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/contact/contact.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/Ui/contact/contact.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/mainview.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/Ui/mainview.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/pc_decrypt/__init__.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/pc_decrypt/decryptUi.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/pc_decrypt/decryptUi.ui" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/app/Ui/pc_decrypt/pc_decrypt.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/decrypt_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/decrypt_window.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/DataBase/micro_msg.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/micro_msg.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/components/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/components/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/person.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/person.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/contact/form.ui" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/mainview.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/mainview.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -119,7 +111,7 @@
</key>
</component>
<component name="RunManager" selected="Python.decrypt_window">
<configuration name="decrypt" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<configuration name="CAvatar" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@ -127,11 +119,32 @@
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/decrypt" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/components" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/decrypt/decrypt.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/components/CAvatar.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="contact_info_ui" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/components" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/components/contact_info_ui.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@ -161,27 +174,6 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="get_wx_info" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/decrypt" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/decrypt/get_wx_info.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="main" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -203,27 +195,6 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="micro_msg (1)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/DataBase" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/DataBase/micro_msg.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="pc_decrypt" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -245,13 +216,34 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test_avatar" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/components" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/components/test_avatar.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.decrypt_window" />
<item itemvalue="Python.contact_info_ui" />
<item itemvalue="Python.test_avatar" />
<item itemvalue="Python.CAvatar" />
<item itemvalue="Python.main" />
<item itemvalue="Python.decrypt" />
<item itemvalue="Python.get_wx_info" />
<item itemvalue="Python.micro_msg (1)" />
</list>
</recent_temporary>
</component>
@ -267,13 +259,6 @@
<option name="presentableId" value="Default" />
<updated>1672848140146</updated>
</task>
<task id="LOCAL-00010" summary="聊天统计">
<created>1675169020409</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1675169020409</updated>
</task>
<task id="LOCAL-00011" summary="优化加载页面">
<created>1675268807882</created>
<option name="number" value="00011" />
@ -610,7 +595,14 @@
<option name="project" value="LOCAL" />
<updated>1700046106844</updated>
</task>
<option name="localTasksCounter" value="59" />
<task id="LOCAL-00059" summary="修改UI">
<created>1700052873083</created>
<option name="number" value="00059" />
<option name="presentableId" value="LOCAL-00059" />
<option name="project" value="LOCAL" />
<updated>1700052873083</updated>
</task>
<option name="localTasksCounter" value="60" />
<servers />
</component>
<component name="UnknownFeatures">
@ -646,7 +638,6 @@
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="readme" />
<MESSAGE value="mainwindows文件修正" />
<MESSAGE value="match语法说明" />
<MESSAGE value="增加群二维码" />
@ -671,7 +662,8 @@
<MESSAGE value="增加PC端微信解密条件的判断" />
<MESSAGE value="删除多余的Word文件" />
<MESSAGE value="修复无法查找wxid的bug" />
<option name="LAST_COMMIT_MESSAGE" value="修复无法查找wxid的bug" />
<MESSAGE value="修改UI" />
<option name="LAST_COMMIT_MESSAGE" value="修改UI" />
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
</component>

View File

@ -1,9 +1,17 @@
import os.path
import sqlite3
from pprint import pprint
DB = sqlite3.connect("./de_MicroMsg.db", check_same_thread=False)
# '''创建游标'''
cursor = DB.cursor()
DB = None
cursor = None
micromsg_path = "./app/Database/Msg/MicroMsg.db"
if os.path.exists(micromsg_path):
DB = sqlite3.connect(micromsg_path, check_same_thread=False)
# '''创建游标'''
cursor = DB.cursor()
def is_database_exist():
return os.path.exists(micromsg_path)
def get_contact():
@ -14,8 +22,8 @@ def get_contact():
'''
cursor.execute(sql)
result = cursor.fetchall()
pprint(result)
print(len(result))
# pprint(result)
# print(len(result))
return result

283
app/components/CAvatar.py Normal file
View File

@ -0,0 +1,283 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2019年7月26日
@author: Irony
@site: https://pyqt5.com https://github.com/892768447
@email: 892768447@qq.com
@file: CustomWidgets.CAvatar
@description: 头像
"""
import os
from PyQt5.QtCore import QUrl, QRectF, Qt, QSize, QTimer, QPropertyAnimation, \
QPointF, pyqtProperty
from PyQt5.QtGui import QPixmap, QColor, QPainter, QPainterPath, QMovie
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkDiskCache, \
QNetworkRequest
from PyQt5.QtWidgets import QWidget, qApp
__Author__ = 'Irony'
__Copyright__ = 'Copyright (c) 2019 Irony'
__Version__ = 1.0
class CAvatar(QWidget):
Circle = 0 # 圆圈
Rectangle = 1 # 圆角矩形
SizeLarge = QSize(128, 128)
SizeMedium = QSize(64, 64)
SizeSmall = QSize(32, 32)
StartAngle = 0 # 起始旋转角度
EndAngle = 360 # 结束旋转角度
def __init__(self, *args, shape=0, url='', cacheDir=False, size=QSize(64, 64), animation=False, **kwargs):
super(CAvatar, self).__init__(*args, **kwargs)
self.url = ''
self._angle = 0 # 角度
self.pradius = 0 # 加载进度条半径
self.animation = animation # 是否使用动画
self._movie = None # 动态图
self._pixmap = QPixmap() # 图片对象
self.pixmap = QPixmap() # 被绘制的对象
self.isGif = url.endswith('.gif')
# 进度动画定时器
self.loadingTimer = QTimer(self, timeout=self.onLoading)
# 旋转动画
self.rotateAnimation = QPropertyAnimation(
self, b'angle', self, loopCount=1)
self.setShape(shape)
self.setCacheDir(cacheDir)
self.setSize(size)
self.setUrl(url)
def paintEvent(self, event):
super(CAvatar, self).paintEvent(event)
# 画笔
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setRenderHint(QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
# 绘制
path = QPainterPath()
diameter = min(self.width(), self.height())
if self.shape == self.Circle:
radius = int(diameter / 2)
elif self.shape == self.Rectangle:
radius = 4
halfW = self.width() / 2
halfH = self.height() / 2
painter.translate(halfW, halfH)
path.addRoundedRect(
QRectF(-halfW, -halfH, diameter, diameter), radius, radius)
painter.setClipPath(path)
# 如果是动画效果
if self.rotateAnimation.state() == QPropertyAnimation.Running:
painter.rotate(self._angle) # 旋转
painter.drawPixmap(
QPointF(-self.pixmap.width() / 2, -self.pixmap.height() // 2), self.pixmap)
else:
painter.drawPixmap(-int(halfW), -int(halfH), self.pixmap)
# 如果在加载
if self.loadingTimer.isActive():
diameter = 2 * self.pradius
painter.setBrush(
QColor(45, 140, 240, int((1 - self.pradius / 10) * 255)))
painter.setPen(Qt.NoPen)
painter.drawRoundedRect(
QRectF(-self.pradius, -self.pradius, diameter, diameter), self.pradius, self.pradius)
def enterEvent(self, event):
"""鼠标进入动画
:param event:
"""
if not (self.animation and not self.isGif):
return
self.rotateAnimation.stop()
cv = self.rotateAnimation.currentValue() or self.StartAngle
self.rotateAnimation.setDuration(
540 if cv == 0 else int(cv / self.EndAngle * 540))
self.rotateAnimation.setStartValue(cv)
self.rotateAnimation.setEndValue(self.EndAngle)
self.rotateAnimation.start()
def leaveEvent(self, event):
"""鼠标离开动画
:param event:
"""
if not (self.animation and not self.isGif):
return
self.rotateAnimation.stop()
cv = self.rotateAnimation.currentValue() or self.EndAngle
self.rotateAnimation.setDuration(int(cv / self.EndAngle * 540))
self.rotateAnimation.setStartValue(cv)
self.rotateAnimation.setEndValue(self.StartAngle)
self.rotateAnimation.start()
def onLoading(self):
"""更新进度动画
"""
if self.loadingTimer.isActive():
if self.pradius > 9:
self.pradius = 0
self.pradius += 1
else:
self.pradius = 0
self.update()
def onFinished(self):
"""图片下载完成
"""
self.loadingTimer.stop()
self.pradius = 0
reply = self.sender()
if self.isGif:
self._movie = QMovie(reply, b'gif', self)
if self._movie.isValid():
self._movie.frameChanged.connect(self._resizeGifPixmap)
self._movie.start()
else:
data = reply.readAll().data()
reply.deleteLater()
del reply
self._pixmap.loadFromData(data)
if self._pixmap.isNull():
self._pixmap = QPixmap(self.size())
self._pixmap.fill(QColor(204, 204, 204))
self._resizePixmap()
def onError(self, code):
"""下载出错了
:param code:
"""
self._pixmap = QPixmap(self.size())
self._pixmap.fill(QColor(204, 204, 204))
self._resizePixmap()
def refresh(self):
"""强制刷新
"""
self._get(self.url)
def isLoading(self):
"""判断是否正在加载
"""
return self.loadingTimer.isActive()
def setShape(self, shape):
"""设置形状
:param shape: 0=圆形, 1=圆角矩形
"""
self.shape = shape
def setUrl(self, url):
"""设置url,可以是本地路径,也可以是网络地址
:param url:
"""
self.url = url
self._get(url)
def setCacheDir(self, cacheDir=''):
"""设置本地缓存路径
:param cacheDir:
"""
self.cacheDir = cacheDir
self._initNetWork()
def setSize(self, size):
"""设置固定尺寸
:param size:
"""
if not isinstance(size, QSize):
size = self.SizeMedium
self.setMinimumSize(size)
self.setMaximumSize(size)
self._resizePixmap()
@pyqtProperty(int)
def angle(self):
return self._angle
@angle.setter
def angle(self, value):
self._angle = value
self.update()
def _resizePixmap(self):
"""缩放图片
"""
if not self._pixmap.isNull():
self.pixmap = self._pixmap.scaled(
self.width(), self.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
self.update()
def _resizeGifPixmap(self, _):
"""缩放动画图片
"""
if self._movie:
self.pixmap = self._movie.currentPixmap().scaled(
self.width(), self.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
self.update()
def _initNetWork(self):
"""初始化异步网络库
"""
if not hasattr(qApp, '_network'):
network = QNetworkAccessManager(self.window())
setattr(qApp, '_network', network)
# 是否需要设置缓存
if self.cacheDir and not qApp._network.cache():
cache = QNetworkDiskCache(self.window())
cache.setCacheDirectory(self.cacheDir)
qApp._network.setCache(cache)
def _get(self, url):
"""设置图片或者请求网络图片
:param url:
"""
if not url:
self.onError('')
return
if url.startswith('http') and not self.loadingTimer.isActive():
url = QUrl(url)
request = QNetworkRequest(url)
# request.setHeader(QNetworkRequest.UserAgentHeader, b'CAvatar')
# request.setRawHeader(b'Author', b'Irony')
request.setAttribute(
QNetworkRequest.FollowRedirectsAttribute, True)
if qApp._network.cache():
request.setAttribute(
QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.PreferNetwork)
request.setAttribute(
QNetworkRequest.CacheSaveControlAttribute, True)
reply = qApp._network.get(request)
self.pradius = 0
self.loadingTimer.start(50) # 显示进度动画
reply.finished.connect(self.onFinished)
reply.error.connect(self.onError)
return
self.pradius = 0
if os.path.exists(url) and os.path.isfile(url):
if self.isGif:
self._movie = QMovie(url, parent=self)
if self._movie.isValid():
self._movie.frameChanged.connect(self._resizeGifPixmap)
self._movie.start()
else:
self._pixmap = QPixmap(url)
self._resizePixmap()
else:
self.onError('')
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = CAvatar(
url='https://wx.qlogo.cn/mmhead/ver_1/DpDqmvTDORNWfLrMj26YicorEUREffl1G8FapawdKgINVH9g1icudfWesGrH9LqeGAz16z4PmkW9U1KAIM3btWgozZ1GaLF66bdKdxlMdazmibn2hpFeiaa4613dN6HM4Vfk/132')
w.show()
sys.exit(app.exec_())

View File

@ -0,0 +1 @@
from .contact_info_ui import ContactQListWidgetItem

View File

@ -0,0 +1,57 @@
import sys
from PyQt5.Qt import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from .CAvatar import CAvatar
# 自定义的item 继承自QListWidgetItem
class ContactQListWidgetItem(QListWidgetItem):
def __init__(self, name, url):
super().__init__()
# 自定义item中的widget 用来显示自定义的内容
self.widget = QWidget()
# 用来显示name
self.nameLabel = QLabel()
self.nameLabel.setText(name)
# 用来显示avator(图像)
self.avatorLabel = CAvatar(None, shape=CAvatar.Rectangle, size=QSize(60, 60),
url=url)
# 设置布局用来对nameLabel和avatorLabel进行布局
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.avatorLabel)
self.hbox.addWidget(self.nameLabel)
self.hbox.addStretch(1)
# 设置widget的布局
self.widget.setLayout(self.hbox)
# 设置自定义的QListWidgetItem的sizeHint不然无法显示
self.setSizeHint(self.widget.sizeHint())
if __name__ == "__main__":
app = QApplication(sys.argv)
# 主窗口
w = QWidget()
w.setWindowTitle("QListWindow")
# 新建QListWidget
listWidget = QListWidget(w)
listWidget.resize(300, 300)
# 新建两个自定义的QListWidgetItem(customQListWidgetItem)
item1 = ContactQListWidgetItem("鲤鱼王", "liyuwang.jpg")
item2 = ContactQListWidgetItem("可达鸭", "kedaya.jpg")
# 在listWidget中加入两个自定义的item
listWidget.addItem(item1)
listWidget.setItemWidget(item1, item1.widget)
listWidget.addItem(item2)
listWidget.setItemWidget(item2, item2.widget)
# 绑定点击槽函数 点击显示对应item中的name
listWidget.itemClicked.connect(lambda item: print(item.nameLabel.text()))
w.show()
sys.exit(app.exec_())

View File

@ -1,4 +1,5 @@
import os.path
from typing import Dict
from PyQt5.QtGui import QPixmap
@ -32,6 +33,18 @@ class Me(Person):
class Contact(Person):
def __init__(self, wxid: str):
super(Contact, self).__init__(wxid)
self.smallHeadImgUrl = ''
self.bigHeadImgUrl = ''
class ContactPC:
def __init__(self, contact_info: Dict):
self.wxid = contact_info.get('UserName')
self.remark = contact_info.get('Remark')
# Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl,bigHeadImgUrl
self.alias = contact_info.get('Alias')
self.nickName = contact_info.get('NickName')
self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl')
class Group(Person):

View File

@ -0,0 +1 @@
from .contact_window import ContactWindow

View File

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'contactUi.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(840, 752)
Form.setStyleSheet("background: rgb(240, 240, 240);")
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setMinimumSize(QtCore.QSize(250, 30))
self.lineEdit.setMaximumSize(QtCore.QSize(250, 16777215))
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit)
self.listWidget = QtWidgets.QListWidget(Form)
self.listWidget.setMinimumSize(QtCore.QSize(250, 0))
self.listWidget.setMaximumSize(QtCore.QSize(250, 16777215))
self.listWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.listWidget.setObjectName("listWidget")
self.verticalLayout.addWidget(self.listWidget)
self.horizontalLayout.addLayout(self.verticalLayout)
self.stackedWidget = QtWidgets.QStackedWidget(Form)
self.stackedWidget.setObjectName("stackedWidget")
self.page = QtWidgets.QWidget()
self.page.setObjectName("page")
self.stackedWidget.addWidget(self.page)
self.page_2 = QtWidgets.QWidget()
self.page_2.setObjectName("page_2")
self.stackedWidget.addWidget(self.page_2)
self.horizontalLayout.addWidget(self.stackedWidget)
self.horizontalLayout.setStretch(1, 1)
self.retranslateUi(Form)
self.stackedWidget.setCurrentIndex(1)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>840</width>
<height>752</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">background: rgb(240, 240, 240);</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>250</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>250</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidget">
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>250</width>
<height>16777215</height>
</size>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="page"/>
<widget class="QWidget" name="page_2"/>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,99 @@
from random import randint
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QListWidgetItem, QLabel, QMessageBox
from app.DataBase import micro_msg
from app.components import ContactQListWidgetItem
from app.person import ContactPC
from .contactUi import Ui_Form
from ...Ui.Icon import Icon
# 美化样式表
Stylesheet = """
/*去掉item虚线边框*/
QListWidget, QListView, QTreeWidget, QTreeView {
outline: 0px;
border:none;
background-color:rgb(240,240,240)
}
/*设置左侧选项的最小最大宽度,文字颜色和背景颜色*/
QListWidget {
min-width: 250px;
max-width: 250px;
min-height: 80px;
max-height: 1200px;
color: black;
border:none;
}
QListWidget::item{
height:60px;
width:250px;
}
/*被选中时的背景颜色和左边框颜色*/
QListWidget::item:selected {
background: rgb(204, 204, 204);
border-bottom: 2px solid rgb(9, 187, 7);
border-left:none;
color: black;
font-weight: bold;
}
/*鼠标悬停颜色*/
HistoryPanel::item:hover {
background: rgb(52, 52, 52);
}
"""
class ContactWindow(QWidget, Ui_Form):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.setStyleSheet(Stylesheet)
self.init_ui()
self.show_contacts()
def init_ui(self):
self.listWidget.clear()
self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
chat_item = QListWidgetItem(Icon.Chat_Icon, '解密', self.listWidget)
contact_item = QListWidgetItem(Icon.Contact_Icon, 'None', self.listWidget)
myinfo_item = QListWidgetItem(Icon.MyInfo_Icon, 'None', self.listWidget)
tool_item = QListWidgetItem(Icon.MyInfo_Icon, 'None', self.listWidget)
label = QLabel('我是页面', self)
label.setAlignment(Qt.AlignCenter)
# 设置label的背景颜色(这里随机)
# 这里加了一个margin边距(方便区分QStackedWidget和QLabel的颜色)
label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % (
randint(0, 255), randint(0, 255), randint(0, 255)))
self.stackedWidget.addWidget(label)
self.stackedWidget.addWidget(label)
self.stackedWidget.addWidget(label)
self.listWidget.setCurrentRow(0)
self.stackedWidget.setCurrentIndex(0)
def show_contacts(self):
if not micro_msg.is_database_exist():
QMessageBox.critical(self, "错误", "数据库不存在\n请先解密数据库")
return
contact_info_lists = micro_msg.get_contact()
for contact_info_list in contact_info_lists:
# UserName, Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl,bigHeadImgUrl
contact_info = {
'UserName': contact_info_list[0],
'Alias': contact_info_list[1],
'Type': contact_info_list[2],
'Remark': contact_info_list[3],
'NickName': contact_info_list[4],
'smallHeadImgUrl': contact_info_list[7]
}
contact = ContactPC(contact_info)
# pprint(contact.__dict__)
contact_item = ContactQListWidgetItem(contact.nickName, contact.smallHeadImgUrl)
self.listWidget.addItem(contact_item)
self.listWidget.setItemWidget(contact_item, contact_item.widget)
def setCurrentIndex(self, row):
print(row)
self.stackedWidget.setCurrentIndex(row)

View File

@ -15,6 +15,7 @@ from PyQt5.QtWidgets import *
from app import config
from app.Ui.Icon import Icon
from . import mainwindow
from .contact import ContactWindow
from .tool import ToolWindow
# 美化样式表
@ -75,22 +76,17 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
contact_item = QListWidgetItem(Icon.Contact_Icon, '好友', self.listWidget)
myinfo_item = QListWidgetItem(Icon.MyInfo_Icon, '我的', self.listWidget)
tool_item = QListWidgetItem(Icon.MyInfo_Icon, '工具', self.listWidget)
tool_window = ToolWindow()
label = QLabel('我是页面', self)
label.setAlignment(Qt.AlignCenter)
# 设置label的背景颜色(这里随机)
# 这里加了一个margin边距(方便区分QStackedWidget和QLabel的颜色)
label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % (
randint(0, 255), randint(0, 255), randint(0, 255)))
self.stackedWidget.addWidget(label)
label = QLabel('我是页面', self)
label.setAlignment(Qt.AlignCenter)
# 设置label的背景颜色(这里随机)
# 这里加了一个margin边距(方便区分QStackedWidget和QLabel的颜色)
label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % (
randint(0, 255), randint(0, 255), randint(0, 255)))
self.stackedWidget.addWidget(label)
contact_window = ContactWindow()
self.stackedWidget.addWidget(contact_window)
label = QLabel('我是页面', self)
label.setAlignment(Qt.AlignCenter)
# 设置label的背景颜色(这里随机)