数据库加锁避免多线程访问报错

This commit is contained in:
shuaikangzhou 2023-11-17 21:34:22 +08:00
parent 142a260f01
commit fc0b1250c4
13 changed files with 574 additions and 111 deletions

View File

@ -4,18 +4,19 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="导出所有数据库的聊天记录">
<change afterPath="$PROJECT_DIR$/doc/images/pc_contact.png" afterDir="false" />
<change afterPath="$PROJECT_DIR$/doc/电脑端使用教程.md" afterDir="false" />
<change afterPath="$PROJECT_DIR$/main_pc.py" afterDir="false" />
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="update readme">
<change afterPath="$PROJECT_DIR$/app/ui_pc/chat/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/ui_pc/chat/chat_info.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/ui_pc/chat/chat_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/DataBase/micro_msg.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/micro_msg.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/DataBase/misc.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/misc.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/DataBase/msg.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/msg.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/components/bubble_message.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/components/bubble_message.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/tool/pc_decrypt/decryptUi.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/decryptUi.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/decryptUi.ui" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/decryptUi.ui" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/pc_decrypt.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/pc_decrypt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/decrypt_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/decrypt_window.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/doc/数据库介绍.md" beforeDir="false" afterPath="$PROJECT_DIR$/doc/数据库介绍.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/readme.md" beforeDir="false" afterPath="$PROJECT_DIR$/readme.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/contact/contactInfoUi.ui" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/contact/contactInfoUi.ui" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/mainview.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/mainview.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/doc/电脑端使用教程.md" beforeDir="false" afterPath="$PROJECT_DIR$/doc/电脑端使用教程.md" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -112,6 +113,48 @@
</key>
</component>
<component name="RunManager" selected="Python.main_pc">
<configuration name="bubble_message" 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/bubble_message.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="chat_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/ui_pc/chat" />
<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/ui_pc/chat/chat_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="decrypt_window" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -133,27 +176,6 @@
<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="" />
<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$" />
<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$/main.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_pc" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -169,7 +191,28 @@
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main_pc.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="EMULATE_TERMINAL" value="true" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="mainview" type="PythonConfigurationType" factoryName="Python" 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/ui_pc" />
<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/ui_pc/mainview.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="true" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
@ -217,34 +260,13 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test" 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$" />
<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$/test.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.main_pc" />
<item itemvalue="Python.decrypt_window" />
<item itemvalue="Python.bubble_message" />
<item itemvalue="Python.chat_info" />
<item itemvalue="Python.msg" />
<item itemvalue="Python.test" />
<item itemvalue="Python.main" />
<item itemvalue="Python.decrypt_window" />
</list>
</recent_temporary>
</component>
@ -260,13 +282,6 @@
<option name="presentableId" value="Default" />
<updated>1672848140146</updated>
</task>
<task id="LOCAL-00018" summary="新增聊天报告">
<created>1682305451381</created>
<option name="number" value="00018" />
<option name="presentableId" value="LOCAL-00018" />
<option name="project" value="LOCAL" />
<updated>1682305451381</updated>
</task>
<task id="LOCAL-00019" summary="readme">
<created>1684598124207</created>
<option name="number" value="00019" />
@ -603,7 +618,14 @@
<option name="project" value="LOCAL" />
<updated>1700147800698</updated>
</task>
<option name="localTasksCounter" value="67" />
<task id="LOCAL-00067" summary="update readme">
<created>1700150198343</created>
<option name="number" value="00067" />
<option name="presentableId" value="LOCAL-00067" />
<option name="project" value="LOCAL" />
<updated>1700150198343</updated>
</task>
<option name="localTasksCounter" value="68" />
<servers />
</component>
<component name="UnknownFeatures">
@ -652,7 +674,6 @@
<MESSAGE value="新增PC数据库解密" />
<MESSAGE value="main首次加载解密界面" />
<MESSAGE value="增加日志模块" />
<MESSAGE value="update readme" />
<MESSAGE value="增加PC端微信解密条件的判断" />
<MESSAGE value="删除多余的Word文件" />
<MESSAGE value="修复无法查找wxid的bug" />
@ -664,7 +685,8 @@
<MESSAGE value="修复情感分析数值显示过长的bug" />
<MESSAGE value="新增聊天记录导出csv格式" />
<MESSAGE value="导出所有数据库的聊天记录" />
<option name="LAST_COMMIT_MESSAGE" value="导出所有数据库的聊天记录" />
<MESSAGE value="update readme" />
<option name="LAST_COMMIT_MESSAGE" value="update readme" />
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
</component>

View File

@ -1,5 +1,6 @@
import os.path
import sqlite3
import time
DB = None
cursor = None
@ -25,6 +26,7 @@ def is_database_exist():
def get_contact():
try:
sql = '''select UserName,Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl.bigHeadImgUrl
from Contact inner join ContactHeadImgUrl on Contact.UserName = ContactHeadImgUrl.usrName
where Type=3 and Alias is not null
@ -32,8 +34,16 @@ def get_contact():
'''
cursor.execute(sql)
result = cursor.fetchall()
# pprint(result)
# print(len(result))
except:
time.sleep(0.2)
sql = '''select UserName,Alias,Type,Remark,NickName,PYInitial,RemarkPYInitial,ContactHeadImgUrl.smallHeadImgUrl,ContactHeadImgUrl.bigHeadImgUrl
from Contact inner join ContactHeadImgUrl on Contact.UserName = ContactHeadImgUrl.usrName
where Type=3 and Alias is not null
order by PYInitial
'''
cursor.execute(sql)
result = cursor.fetchall()
# DB.commit()
return result

View File

@ -1,6 +1,8 @@
import os.path
import sqlite3
import threading
lock = threading.Lock()
DB = None
cursor = None
misc_path = "./app/Database/Msg/Misc.db"
@ -17,11 +19,15 @@ def get_avatar_buffer(userName):
from ContactHeadImg1
where usrName=?;
'''
try:
lock.acquire(True)
cursor.execute(sql, [userName])
result = cursor.fetchall()
# print(result[0][0])
if result:
return result[0][0]
finally:
lock.release()
return None

View File

@ -1,10 +1,12 @@
import os.path
import re
import sqlite3
import threading
DB = []
cursor = []
msg_root_path = "./app/Database/Msg/"
lock = threading.Lock()
# misc_path = './Msg/Misc.db'
if os.path.exists(msg_root_path):
for root, dirs, files in os.walk(msg_root_path):
@ -54,18 +56,41 @@ def get_messages(username_):
return result
def get_message_by_num(username_, n):
sql = '''
select localId,TalkerId,Type,SubType,IsSender,CreateTime,Status,StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime
from MSG
where StrTalker=?
order by CreateTime
limit 10
'''
result = []
try:
lock.acquire(True)
for cur in cursor:
cur = cursor[-1]
cur.execute(sql, [username_])
result_ = cur.fetchall()
result += result_
return result_
finally:
lock.release()
result.sort(key=lambda x: x[5])
return result
def close():
for db in DB:
db.close()
if __name__ == '__main__':
from pprint import pprint
msg_root_path = './Msg/'
init_database()
username = 'wxid_0o18ef858vnu22'
result = get_messages(username)
pprint(result)
pprint(len(result))
# username = 'wxid_0o18ef858vnu22'
# result = get_messages(username)
# pprint(result)
# pprint(len(result))
result = get_message_by_num('wxid_0o18ef858vnu22', 0)
print(result)

View File

@ -1,9 +1,9 @@
from PIL import Image
from PyQt5 import QtGui
from PyQt5.QtCore import QSize, pyqtSignal, Qt, QThread
from PyQt5.QtGui import QPainter, QFont, QColor, QPixmap, QPolygon
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QSizePolicy, QVBoxLayout, QSpacerItem, \
QScrollArea, QScrollBar
from PyQt5.QtCore import QSize, pyqtSignal, Qt, QThread
class TextMessage(QLabel):
@ -11,13 +11,14 @@ class TextMessage(QLabel):
def __init__(self, text, is_send=False, parent=None):
super(TextMessage, self).__init__(text, parent)
self.setFont(QFont('SimSun', 15))
self.setFont(QFont('微软雅黑', 12))
self.setWordWrap(True)
# self.adjustSize()
self.setMaximumWidth(800)
self.setMinimumWidth(100)
self.setMinimumHeight(10)
self.setMinimumHeight(45)
# self.resize(QSize(100,40))
self.setTextInteractionFlags(Qt.TextSelectableByMouse)
self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
# self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Minimum)
@ -44,6 +45,9 @@ class TextMessage(QLabel):
border-left: 10px solid #b2e281;
'''
)
w = len(text) * 16 + 30
if w < self.width():
self.setMaximumWidth(w)
def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
super(TextMessage, self).paintEvent(a0)
@ -58,7 +62,7 @@ class Triangle(QLabel):
def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
super(Triangle, self).paintEvent(a0)
if self.Type == 3:
if self.Type == 1:
painter = QPainter(self)
triangle = QPolygon()
# print(self.width(), self.height())
@ -90,9 +94,8 @@ class Avatar(QLabel):
self.setPixmap(QPixmap(avatar).scaled(45, 45))
self.image_path = avatar
elif isinstance(avatar, QPixmap):
self.setPixmap(avatar)
self.setMaximumWidth(45)
self.setMaximumHeight(45)
self.setPixmap(avatar.scaled(45, 45))
self.setFixedSize(QSize(45, 45))
class OpenImageThread(QThread):
@ -108,7 +111,6 @@ class OpenImageThread(QThread):
class ImageMessage(QLabel):
def __init__(self, avatar, parent=None):
super().__init__(parent)
self.image_path = './Data/head.jpg'
self.image = QLabel(self)
if isinstance(avatar, str):
self.setPixmap(QPixmap(avatar))
@ -117,6 +119,7 @@ class ImageMessage(QLabel):
self.setPixmap(avatar)
self.setMaximumWidth(480)
self.setMaximumHeight(720)
self.setScaledContents(True)
def mousePressEvent(self, event):
if event.buttons() == Qt.LeftButton: # 左键按下
@ -139,8 +142,9 @@ class BubbleMessage(QWidget):
layout.setContentsMargins(0, 5, 5, 5)
self.avatar = Avatar(avatar)
triangle = Triangle(Type, is_send)
if Type == 3:
if Type == 1:
self.message = TextMessage(str_content, is_send)
# self.message.setMaximumWidth(int(self.width() * 0.6))
else:
self.message = ImageMessage(str_content)
# skin_aio_friend_bubble_pressed.9
@ -169,6 +173,11 @@ class BubbleMessage(QWidget):
class ScrollAreaContent(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# self.setStyleSheet(
# '''
# background-color:rgb(127,127,127);
# '''
# )
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
# print(self.width(),self.height())
@ -246,8 +255,8 @@ class MyWidget(QWidget):
super().__init__()
self.resize(500, 200)
txt = '''在工具中单击边缘可以添加黑点,单击可以删掉黑点,拖动可以调整黑点长度。勾选等选项可以查看内容、缩放等区域右侧可预览不同拉伸情况下的效果,拖动可以调整预览的拉伸比例'''
avatar = 'Data/head.jpg'
bubble_message = BubbleMessage(txt, avatar, Type=3, is_send=False)
avatar = '../data/icons/default_avatar.svg'
bubble_message = BubbleMessage(txt, avatar, Type=1, is_send=False)
layout = QVBoxLayout()
layout.setSpacing(0)
@ -265,31 +274,44 @@ class MyWidget(QWidget):
layout.addWidget(self.scrollArea)
layout0 = QVBoxLayout()
layout0.setSpacing(0)
self.scrollArea.setLayout(layout0)
# self.scrollArea.setLayout(layout0)
self.scrollAreaWidgetContents.setLayout(layout0)
time = Notice("2023-11-17 15:44")
layout0.addWidget(time)
txt = "你说啥"
avatar_2 = 'Data/fg1.png'
bubble_message1 = BubbleMessage(txt, avatar_2, Type=3, is_send=True)
avatar_2 = '../data/icons/default_avatar.svg'
bubble_message1 = BubbleMessage(txt, avatar_2, Type=1, is_send=True)
layout0.addWidget(bubble_message)
layout0.addWidget(bubble_message1)
bubble_message2 = BubbleMessage('', avatar_2, Type=3, is_send=True)
bubble_message2 = BubbleMessage('', avatar_2, Type=1, is_send=True)
layout0.addWidget(bubble_message2)
txt = "我啥都没说"
avatar0 = 'Data/fg1.png'
bubble_message1 = BubbleMessage('Data/fg1.png', avatar, Type=1, is_send=False)
bubble_message1 = BubbleMessage("D:\Project\Python\PyQt-master\QLabel\Data\\fg1.png", avatar, Type=3,
is_send=False)
layout0.addWidget(bubble_message1)
self.spacerItem = QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
layout0.addItem(self.spacerItem)
layout.setStretch(0, 1)
# layout.setStretch(0, 1)
self.setLayout(layout)
class Test(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
w1 = MyWidget()
w2 = QLabel("nihao")
layout.addWidget(w1)
layout.addWidget(w2)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication([])
widget = MyWidget()
widget = Test()
# widget = MyWidget()
widget.show()
app.exec_()

View File

@ -39,6 +39,42 @@ class Contact(Person):
self.bigHeadImgUrl = ''
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class MePC:
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')
if not self.remark:
self.remark = self.nickName
self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl')
self.smallHeadImgBLOG = b''
self.avatar = QPixmap()
def set_avatar(self, img_bytes):
if not img_bytes:
self.avatar.load(Icon.Default_avatar_path)
return
if img_bytes[:4] == b'\x89PNG':
self.avatar.loadFromData(img_bytes, format='PNG')
else:
self.avatar.loadFromData(img_bytes, format='jfif')
self.avatar.scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
class ContactPC:
def __init__(self, contact_info: Dict):
self.wxid = contact_info.get('UserName')
@ -66,3 +102,7 @@ class ContactPC:
class Group(Person):
def __init__(self, wxid: str):
super(Group, self).__init__(wxid)
if __name__ == '__main__':
pass

View File

@ -0,0 +1 @@
from .chat_window import ChatWindow

View File

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'chatInfoUi.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(817, 748)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout")
self.frame = QtWidgets.QFrame(Form)
self.frame.setFrameShape(QtWidgets.QFrame.NoFrame)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_reamrk = QtWidgets.QLabel(self.frame)
self.label_reamrk.setObjectName("label_reamrk")
self.horizontalLayout_2.addWidget(self.label_reamrk)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem)
self.toolButton = QtWidgets.QToolButton(self.frame)
self.toolButton.setObjectName("toolButton")
self.horizontalLayout_2.addWidget(self.toolButton)
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
self.verticalLayout.addWidget(self.frame)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label_reamrk.setText(_translate("Form", "TextLabel"))
self.toolButton.setText(_translate("Form", "..."))

View File

@ -0,0 +1,96 @@
<?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>817</width>
<height>748</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<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>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_reamrk">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="toolButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>797</width>
<height>700</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,78 @@
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QSpacerItem, QSizePolicy
from app.DataBase import msg
from app.components.bubble_message import BubbleMessage, ScrollBar, ScrollArea, ScrollAreaContent
from .chatInfoUi import Ui_Form
class ChatInfo(QWidget, Ui_Form):
def __init__(self, contact, parent=None):
super().__init__(parent)
self.scrollArea = None
self.setupUi(self)
self.contact = contact
self.init_ui()
self.show_chats()
def init_ui(self):
self.label_reamrk.setText(self.contact.remark)
self.scrollArea = ScrollArea()
self.verticalLayout_2.addWidget(self.scrollArea, 1)
self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scrollBar = ScrollBar()
self.scrollArea.setVerticalScrollBar(scrollBar)
self.scrollAreaWidgetContents = ScrollAreaContent()
self.scrollAreaWidgetContents.setMinimumSize(200, 100)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.scroolAreaLayout = QVBoxLayout()
self.scrollAreaWidgetContents.setLayout(self.scroolAreaLayout)
def show_chats(self):
self.show_chat_thread = ShowChatThread(self.contact)
self.show_chat_thread.showSingal.connect(self.show_chat)
self.show_chat_thread.finishSingal.connect(self.show_finish)
self.show_chat_thread.start()
def show_finish(self, ok):
self.spacerItem = QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.scroolAreaLayout.addItem(self.spacerItem)
def show_chat(self, message):
try:
type_ = message[2]
# print(type_, type(type_))
if type_ == 1:
str_content = message[7]
is_send = message[4]
bubble_message = BubbleMessage(
str_content,
self.contact.avatar,
type_,
is_send
)
# print(str_content)
self.scroolAreaLayout.addWidget(bubble_message)
except:
print(message)
class ShowChatThread(QThread):
showSingal = pyqtSignal(tuple)
finishSingal = pyqtSignal(int)
# heightSingal = pyqtSignal(int)
def __init__(self, contact):
super().__init__()
self.wxid = contact.wxid
def run(self) -> None:
messages = msg.get_message_by_num(self.wxid, 0)
for message in messages:
self.showSingal.emit(message)
self.finishSingal.emit(1)

View File

@ -0,0 +1,115 @@
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QLineEdit
from app.DataBase import micro_msg, misc
from app.components import ContactQListWidgetItem
from app.person import ContactPC
from .chatUi import Ui_Form
from .chat_info import ChatInfo
from ..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 ChatWindow(QWidget, Ui_Form):
def __init__(self, parent=None):
super().__init__(parent)
self.show_thread = None
self.setupUi(self)
self.ok_flag = False
self.setStyleSheet(Stylesheet)
self.init_ui()
self.show_chats()
def init_ui(self):
search_action = QAction(self.lineEdit)
search_action.setIcon(Icon.Search_Icon)
self.lineEdit.addAction(search_action, QLineEdit.LeadingPosition)
self.listWidget.clear()
self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
self.listWidget.setCurrentRow(0)
self.stackedWidget.setCurrentIndex(0)
def show_chats(self):
print('chat0')
if self.ok_flag:
return
micro_msg.init_database()
if not micro_msg.is_database_exist():
QMessageBox.critical(self, "错误", "数据库不存在\n请先解密数据库")
return
self.show_thread = ShowContactThread()
self.show_thread.showSingal.connect(self.show_chat)
self.show_thread.start()
self.ok_flag = True
def show_chat(self, contact):
contact_item = ContactQListWidgetItem(contact.nickName, contact.smallHeadImgUrl, contact.smallHeadImgBLOG)
self.listWidget.addItem(contact_item)
self.listWidget.setItemWidget(contact_item, contact_item.widget)
chat_info_window = ChatInfo(contact)
self.stackedWidget.addWidget(chat_info_window)
def setCurrentIndex(self, row):
print(row)
self.stackedWidget.setCurrentIndex(row)
class ShowContactThread(QThread):
showSingal = pyqtSignal(ContactPC)
# heightSingal = pyqtSignal(int)
def __init__(self):
super().__init__()
def run(self) -> None:
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)
contact.smallHeadImgBLOG = misc.get_avatar_buffer(contact.wxid)
contact.set_avatar(contact.smallHeadImgBLOG)
self.showSingal.emit(contact)
# pprint(contact.__dict__)

View File

@ -16,6 +16,7 @@ from app import config
from app.DataBase import msg
from app.Ui.Icon import Icon
from . import mainwindow
from .chat import ChatWindow
from .contact import ContactWindow
from .tool import ToolWindow
@ -67,6 +68,7 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
self.setWindowIcon(Icon.MainWindow_Icon)
self.setStyleSheet(Stylesheet)
self.listWidget.clear()
self.resize(QSize(800, 600))
# self.stackedWidget = QtWidgets.QStackedWidget(self.centralwidget)
self.action_desc.triggered.connect(self.about)
self.init_ui()
@ -79,14 +81,10 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
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)
self.chat_window = ChatWindow()
self.stackedWidget.addWidget(self.chat_window)
self.contact_window = ContactWindow()
# self.contact_window = QWidget()
self.stackedWidget.addWidget(self.contact_window)
label = QLabel('我是页面', self)
label.setAlignment(Qt.AlignCenter)

View File

@ -37,6 +37,7 @@ pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
4. 设置微信安装路径
可以到微信->设置->文件管理查看
![](./images/setting.png)
点击**设置微信路径**按钮,选择该文件夹路径