init
This commit is contained in:
103
app/components/Button_Contact.py
Normal file
103
app/components/Button_Contact.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from PyQt5.QtCore import *
|
||||
|
||||
from app import person
|
||||
|
||||
|
||||
class ContactUi(QtWidgets.QPushButton):
|
||||
"""
|
||||
联系人类,继承自pyqt的按钮,里面封装了联系人头像等标签
|
||||
"""
|
||||
usernameSingal = pyqtSignal(str)
|
||||
|
||||
def __init__(self, Ui, id=None, rconversation=None):
|
||||
super(ContactUi, self).__init__(Ui)
|
||||
self.contact: person.Contact = person.Contact(rconversation[1])
|
||||
self.init_ui(Ui)
|
||||
self.msgCount = rconversation[0]
|
||||
self.username = rconversation[1]
|
||||
self.conversationTime = rconversation[6]
|
||||
self.msgType = rconversation[7]
|
||||
self.digest = rconversation[8]
|
||||
hasTrunc = rconversation[10]
|
||||
attrflag = rconversation[11]
|
||||
if hasTrunc == 0:
|
||||
if attrflag == 0:
|
||||
self.digest = '[动画表情]'
|
||||
elif attrflag == 67108864:
|
||||
try:
|
||||
remark = data.get_conRemark(rconversation[9])
|
||||
msg = self.digest.split(':')[1].strip('\n').strip()
|
||||
self.digest = f'{remark}:{msg}'
|
||||
except Exception as e:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
self.show_info(id)
|
||||
|
||||
def init_ui(self, Ui):
|
||||
self.layoutWidget = QtWidgets.QWidget(Ui)
|
||||
self.layoutWidget.setObjectName("layoutWidget")
|
||||
self.gridLayout1 = QtWidgets.QGridLayout(self.layoutWidget)
|
||||
self.gridLayout1.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
|
||||
self.gridLayout1.setContentsMargins(10, 10, 10, 10)
|
||||
self.gridLayout1.setSpacing(10)
|
||||
self.gridLayout1.setObjectName("gridLayout1")
|
||||
self.label_time = QtWidgets.QLabel(self.layoutWidget)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(8)
|
||||
self.label_time.setFont(font)
|
||||
self.label_time.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.label_time.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
|
||||
self.label_time.setObjectName("label_time")
|
||||
self.gridLayout1.addWidget(self.label_time, 0, 2, 1, 1)
|
||||
self.label_remark = QtWidgets.QLabel(self.layoutWidget)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("黑体")
|
||||
font.setPointSize(10)
|
||||
# font.setBold(True)
|
||||
self.label_remark.setFont(font)
|
||||
self.label_remark.setObjectName("label_remark")
|
||||
self.gridLayout1.addWidget(self.label_remark, 0, 1, 1, 1)
|
||||
self.label_msg = QtWidgets.QLabel(self.layoutWidget)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("微软雅黑")
|
||||
font.setPointSize(8)
|
||||
self.label_msg.setFont(font)
|
||||
self.label_msg.setObjectName("label_msg")
|
||||
self.gridLayout1.addWidget(self.label_msg, 1, 1, 1, 2)
|
||||
self.label_avatar = QtWidgets.QLabel(self.layoutWidget)
|
||||
self.label_avatar.setMinimumSize(QtCore.QSize(60, 60))
|
||||
self.label_avatar.setMaximumSize(QtCore.QSize(60, 60))
|
||||
self.label_avatar.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.label_avatar.setAutoFillBackground(False)
|
||||
self.label_avatar.setStyleSheet("background-color: #ffffff;")
|
||||
self.label_avatar.setInputMethodHints(QtCore.Qt.ImhNone)
|
||||
self.label_avatar.setFrameShape(QtWidgets.QFrame.NoFrame)
|
||||
self.label_avatar.setFrameShadow(QtWidgets.QFrame.Plain)
|
||||
self.label_avatar.setAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.label_avatar.setObjectName("label_avatar")
|
||||
self.gridLayout1.addWidget(self.label_avatar, 0, 0, 2, 1)
|
||||
self.gridLayout1.setColumnStretch(0, 1)
|
||||
self.gridLayout1.setColumnStretch(1, 6)
|
||||
self.gridLayout1.setRowStretch(0, 5)
|
||||
self.gridLayout1.setRowStretch(1, 3)
|
||||
self.setLayout(self.gridLayout1)
|
||||
self.setStyleSheet(
|
||||
"QPushButton {background-color: rgb(220,220,220);}"
|
||||
"QPushButton:hover{background-color: rgb(208,208,208);}\n"
|
||||
)
|
||||
|
||||
def show_info(self, id):
|
||||
time = datetime.now().strftime("%m-%d %H:%M")
|
||||
msg = '还没说话'
|
||||
self.label_avatar.setPixmap(self.contact.avatar) # 在label上显示图片
|
||||
self.label_remark.setText(self.contact.conRemark)
|
||||
self.label_msg.setText(self.digest)
|
||||
self.label_time.setText(data.timestamp2str(self.conversationTime)[2:])
|
||||
|
||||
def show_msg(self):
|
||||
self.usernameSingal.emit(self.username)
|
||||
303
app/components/CAvatar.py
Normal file
303
app/components/CAvatar.py
Normal file
File diff suppressed because one or more lines are too long
71
app/components/QCursorGif.py
Normal file
71
app/components/QCursorGif.py
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2020年3月13日
|
||||
@author: Irony
|
||||
@site: https://pyqt.site , https://github.com/PyQt5
|
||||
@email: 892768447@qq.com
|
||||
@file: Demo.Lib.QCursorGif
|
||||
@description:
|
||||
"""
|
||||
|
||||
try:
|
||||
from PyQt5.QtCore import QTimer, Qt
|
||||
from PyQt5.QtGui import QCursor, QPixmap
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
except ImportError:
|
||||
from PySide2.QtCore import QTimer, Qt
|
||||
from PySide2.QtGui import QCursor, QPixmap
|
||||
from PySide2.QtWidgets import QApplication
|
||||
from app.resources import resource_rc
|
||||
|
||||
var = resource_rc.qt_resource_name
|
||||
|
||||
|
||||
class QCursorGif:
|
||||
|
||||
def initCursor(self, cursors, parent=None):
|
||||
# 记录默认的光标
|
||||
self._oldCursor = Qt.ArrowCursor
|
||||
self.setOldCursor(parent)
|
||||
# 加载光标图片
|
||||
self._cursorImages = [
|
||||
QCursor(QPixmap(cursor)) for cursor in cursors]
|
||||
self._cursorIndex = 0
|
||||
self._cursorCount = len(self._cursorImages) - 1
|
||||
# 创建刷新定时器
|
||||
self._cursorTimeout = 200
|
||||
self._cursorTimer = QTimer(parent)
|
||||
self._cursorTimer.timeout.connect(self._doBusy)
|
||||
self.num = 0
|
||||
|
||||
def _doBusy(self):
|
||||
if self._cursorIndex > self._cursorCount:
|
||||
self._cursorIndex = 0
|
||||
QApplication.setOverrideCursor(
|
||||
self._cursorImages[self._cursorIndex])
|
||||
self._cursorIndex += 1
|
||||
self.num += 1
|
||||
|
||||
def startBusy(self):
|
||||
# QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
if not self._cursorTimer.isActive():
|
||||
self._cursorTimer.start(self._cursorTimeout)
|
||||
|
||||
def stopBusy(self):
|
||||
self._cursorTimer.stop()
|
||||
QApplication.restoreOverrideCursor()
|
||||
# 将光标出栈,恢复至原始状态
|
||||
for i in range(self.num):
|
||||
QApplication.restoreOverrideCursor()
|
||||
self.num = 0
|
||||
|
||||
|
||||
def setCursorTimeout(self, timeout):
|
||||
self._cursorTimeout = timeout
|
||||
|
||||
def setOldCursor(self, parent=None):
|
||||
QApplication.overrideCursor()
|
||||
self._oldCursor = (QApplication.overrideCursor() or parent.cursor() or Qt.ArrowCursor or Qt.IBeamCursor) if parent else (
|
||||
QApplication.overrideCursor() or Qt.ArrowCursor)
|
||||
2
app/components/__init__.py
Normal file
2
app/components/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .contact_info_ui import ContactQListWidgetItem
|
||||
from .scroll_bar import ScrollBar
|
||||
301
app/components/bubble_message.py
Normal file
301
app/components/bubble_message.py
Normal file
@@ -0,0 +1,301 @@
|
||||
import os.path
|
||||
import subprocess
|
||||
import platform
|
||||
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtCore import QSize, pyqtSignal, Qt, QThread
|
||||
from PyQt5.QtGui import QPainter, QFont, QColor, QPixmap, QPolygon, QFontMetrics
|
||||
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QVBoxLayout, QSpacerItem, \
|
||||
QScrollArea
|
||||
|
||||
from app.components.scroll_bar import ScrollBar
|
||||
|
||||
|
||||
class MessageType:
|
||||
Text = 1
|
||||
Image = 3
|
||||
|
||||
|
||||
class TextMessage(QLabel):
|
||||
heightSingal = pyqtSignal(int)
|
||||
|
||||
def __init__(self, text, is_send=False, parent=None):
|
||||
if isinstance(text, bytes):
|
||||
text = text.decode('utf-8')
|
||||
super(TextMessage, self).__init__(text, parent)
|
||||
font = QFont('微软雅黑', 12)
|
||||
self.setFont(font)
|
||||
self.setWordWrap(True)
|
||||
self.setMaximumWidth(800)
|
||||
# self.setMinimumWidth(100)
|
||||
self.setMinimumHeight(45)
|
||||
self.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
|
||||
if is_send:
|
||||
self.setAlignment(Qt.AlignCenter | Qt.AlignRight)
|
||||
self.setStyleSheet(
|
||||
'''
|
||||
background-color:#b2e281;
|
||||
border-radius:10px;
|
||||
padding:10px;
|
||||
'''
|
||||
)
|
||||
else:
|
||||
self.setStyleSheet(
|
||||
'''
|
||||
background-color:white;
|
||||
border-radius:10px;
|
||||
padding:10px;
|
||||
'''
|
||||
)
|
||||
font_metrics = QFontMetrics(font)
|
||||
rect = font_metrics.boundingRect(text)
|
||||
# rect = font_metrics
|
||||
self.setMaximumWidth(rect.width() + 40)
|
||||
|
||||
def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
|
||||
super(TextMessage, self).paintEvent(a0)
|
||||
|
||||
|
||||
class Triangle(QLabel):
|
||||
def __init__(self, Type, is_send=False, position=(0, 0), parent=None):
|
||||
"""
|
||||
|
||||
@param Type:
|
||||
@param is_send:
|
||||
@param position:(x,y)
|
||||
@param parent:
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.Type = Type
|
||||
self.is_send = is_send
|
||||
self.position = position
|
||||
|
||||
def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
|
||||
|
||||
super(Triangle, self).paintEvent(a0)
|
||||
if self.Type == MessageType.Text:
|
||||
self.setFixedSize(6, 45)
|
||||
painter = QPainter(self)
|
||||
triangle = QPolygon()
|
||||
x, y = self.position
|
||||
if self.is_send:
|
||||
painter.setPen(QColor('#b2e281'))
|
||||
painter.setBrush(QColor('#b2e281'))
|
||||
triangle.setPoints(0, 20+y, 0, 34+y, 6, 27+y)
|
||||
else:
|
||||
painter.setPen(QColor('white'))
|
||||
painter.setBrush(QColor('white'))
|
||||
triangle.setPoints(0, 27+y, 6, 20+y, 6, 34+y)
|
||||
painter.drawPolygon(triangle)
|
||||
|
||||
|
||||
class Notice(QLabel):
|
||||
def __init__(self, text, type_=3, parent=None):
|
||||
super().__init__(text, parent)
|
||||
self.type_ = type_
|
||||
self.setFont(QFont('微软雅黑', 10))
|
||||
self.setWordWrap(True)
|
||||
self.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
self.setAlignment(Qt.AlignCenter)
|
||||
|
||||
|
||||
class Avatar(QLabel):
|
||||
def __init__(self, avatar, parent=None):
|
||||
super().__init__(parent)
|
||||
if isinstance(avatar, str):
|
||||
self.setPixmap(QPixmap(avatar).scaled(45, 45))
|
||||
self.image_path = avatar
|
||||
elif isinstance(avatar, QPixmap):
|
||||
self.setPixmap(avatar.scaled(45, 45))
|
||||
self.setFixedSize(QSize(45, 45))
|
||||
|
||||
|
||||
def open_image_viewer(file_path):
|
||||
system_platform = platform.system()
|
||||
|
||||
if system_platform == "Darwin": # macOS
|
||||
subprocess.run(["open", file_path])
|
||||
elif system_platform == "Windows":
|
||||
subprocess.run(["start", " ", file_path], shell=True)
|
||||
elif system_platform == "Linux":
|
||||
subprocess.run(["xdg-open", file_path])
|
||||
else:
|
||||
print("Unsupported platform")
|
||||
|
||||
|
||||
class OpenImageThread(QThread):
|
||||
def __init__(self, image_path):
|
||||
super().__init__()
|
||||
self.image_path = image_path
|
||||
|
||||
def run(self) -> None:
|
||||
if os.path.exists(self.image_path):
|
||||
open_image_viewer(self.image_path)
|
||||
|
||||
|
||||
class ImageMessage(QLabel):
|
||||
def __init__(self, image, is_send, image_link='', max_width=480, max_height=240, parent=None):
|
||||
"""
|
||||
param:image 图像路径或者QPixmap对象
|
||||
param:image_link='' 点击图像打开的文件路径
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.image = QLabel(self)
|
||||
self.max_width = max_width
|
||||
self.max_height = max_height
|
||||
# self.setFixedSize(self.max_width,self.max_height)
|
||||
self.setMaximumWidth(self.max_width)
|
||||
self.setMaximumHeight(self.max_height)
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
if isinstance(image, str):
|
||||
pixmap = QPixmap(image)
|
||||
self.image_path = image
|
||||
elif isinstance(image, QPixmap):
|
||||
pixmap = image
|
||||
self.set_image(pixmap)
|
||||
if image_link:
|
||||
self.image_path = image_link
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
if is_send:
|
||||
self.setAlignment(Qt.AlignCenter | Qt.AlignRight)
|
||||
# self.setScaledContents(True)
|
||||
|
||||
def set_image(self, pixmap):
|
||||
# 计算调整后的大小
|
||||
adjusted_width = min(pixmap.width(), self.max_width)
|
||||
adjusted_height = min(pixmap.height(), self.max_height)
|
||||
self.setPixmap(pixmap.scaled(adjusted_width, adjusted_height, Qt.KeepAspectRatio))
|
||||
# 调整QLabel的大小以适应图片的宽高,但不超过最大宽高
|
||||
# self.setFixedSize(adjusted_width, adjusted_height)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.buttons() == Qt.LeftButton: # 左键按下
|
||||
print('打开图像', self.image_path)
|
||||
self.open_image_thread = OpenImageThread(self.image_path)
|
||||
self.open_image_thread.start()
|
||||
|
||||
|
||||
class BubbleMessage(QWidget):
|
||||
def __init__(self, str_content, avatar, Type, is_send=False, display_name=None, parent=None):
|
||||
super().__init__(parent)
|
||||
self.isSend = is_send
|
||||
# self.set
|
||||
self.setStyleSheet(
|
||||
'''
|
||||
border:none;
|
||||
'''
|
||||
)
|
||||
layout = QHBoxLayout()
|
||||
layout.setSpacing(0)
|
||||
layout.setContentsMargins(0, 5, 5, 5)
|
||||
# self.resize(QSize(200, 50))
|
||||
self.avatar = Avatar(avatar)
|
||||
triangle = Triangle(Type, is_send, (0, 0))
|
||||
if Type == MessageType.Text:
|
||||
self.message = TextMessage(str_content, is_send)
|
||||
# self.message.setMaximumWidth(int(self.width() * 0.6))
|
||||
elif Type == MessageType.Image:
|
||||
self.message = ImageMessage(str_content, is_send)
|
||||
else:
|
||||
raise ValueError("未知的消息类型")
|
||||
if display_name:
|
||||
triangle = Triangle(Type, is_send, (0, 10))
|
||||
label_name = QLabel(display_name, self)
|
||||
label_name.setFont(QFont('微软雅黑', 10))
|
||||
if is_send:
|
||||
label_name.setAlignment(Qt.AlignRight)
|
||||
vlayout = QVBoxLayout()
|
||||
vlayout.setSpacing(0)
|
||||
if is_send:
|
||||
vlayout.addWidget(label_name, 0, Qt.AlignTop | Qt.AlignRight)
|
||||
vlayout.addWidget(self.message, 0, Qt.AlignTop | Qt.AlignRight)
|
||||
else:
|
||||
vlayout.addWidget(label_name)
|
||||
vlayout.addWidget(self.message)
|
||||
self.spacerItem = QSpacerItem(45 + 6, 45, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
if is_send:
|
||||
layout.addItem(self.spacerItem)
|
||||
if display_name:
|
||||
layout.addLayout(vlayout, 1)
|
||||
else:
|
||||
layout.addWidget(self.message, 1)
|
||||
layout.addWidget(triangle, 0, Qt.AlignTop | Qt.AlignLeft)
|
||||
layout.addWidget(self.avatar, 0, Qt.AlignTop | Qt.AlignLeft)
|
||||
else:
|
||||
layout.addWidget(self.avatar, 0, Qt.AlignTop | Qt.AlignRight)
|
||||
layout.addWidget(triangle, 0, Qt.AlignTop | Qt.AlignRight)
|
||||
if display_name:
|
||||
layout.addLayout(vlayout, 1)
|
||||
else:
|
||||
layout.addWidget(self.message, 1)
|
||||
layout.addItem(self.spacerItem)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
class ScrollAreaContent(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.adjustSize()
|
||||
|
||||
|
||||
class ScrollArea(QScrollArea):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWidgetResizable(True)
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
self.setStyleSheet(
|
||||
'''
|
||||
border:none;
|
||||
'''
|
||||
)
|
||||
|
||||
|
||||
class ChatWidget(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.resize(500, 200)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.setSpacing(0)
|
||||
self.adjustSize()
|
||||
# 生成滚动区域
|
||||
self.scrollArea = ScrollArea(self)
|
||||
scrollBar = ScrollBar()
|
||||
self.scrollArea.setVerticalScrollBar(scrollBar)
|
||||
# 生成滚动区域的内容部署层部件
|
||||
self.scrollAreaWidgetContents = ScrollAreaContent(self.scrollArea)
|
||||
self.scrollAreaWidgetContents.setMinimumSize(50, 100)
|
||||
# 设置滚动区域的内容部署部件为前面生成的内容部署层部件
|
||||
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
|
||||
layout.addWidget(self.scrollArea)
|
||||
self.layout0 = QVBoxLayout()
|
||||
self.layout0.setSpacing(0)
|
||||
self.scrollAreaWidgetContents.setLayout(self.layout0)
|
||||
self.setLayout(layout)
|
||||
|
||||
def add_message_item(self, bubble_message, index=1):
|
||||
if index:
|
||||
self.layout0.addWidget(bubble_message)
|
||||
else:
|
||||
self.layout0.insertWidget(0, bubble_message)
|
||||
# self.set_scroll_bar_last()
|
||||
|
||||
def set_scroll_bar_last(self):
|
||||
self.scrollArea.verticalScrollBar().setValue(
|
||||
self.scrollArea.verticalScrollBar().maximum()
|
||||
)
|
||||
|
||||
def set_scroll_bar_value(self, val):
|
||||
self.verticalScrollBar().setValue(val)
|
||||
|
||||
def verticalScrollBar(self):
|
||||
return self.scrollArea.verticalScrollBar()
|
||||
|
||||
def update(self) -> None:
|
||||
super().update()
|
||||
self.scrollAreaWidgetContents.adjustSize()
|
||||
self.scrollArea.update()
|
||||
# self.scrollArea.repaint()
|
||||
# self.verticalScrollBar().setMaximum(self.scrollAreaWidgetContents.height())
|
||||
78
app/components/calendar_dialog.py
Normal file
78
app/components/calendar_dialog.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import time
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QApplication, QDialog, QCheckBox, QMessageBox, QCalendarWidget, QWidget, QVBoxLayout, \
|
||||
QToolButton
|
||||
|
||||
from app.ui.Icon import Icon
|
||||
|
||||
|
||||
class CalendarDialog(QDialog):
|
||||
selected_date_signal = pyqtSignal(int)
|
||||
|
||||
def __init__(self, date_range=None, parent=None):
|
||||
"""
|
||||
|
||||
@param date_range: tuple[Union[QDate, datetime.date],Union[QDate, datetime.date]] #限定的可选择范围
|
||||
@param parent:
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle('选择日期')
|
||||
self.calendar = QCalendarWidget(self)
|
||||
self.calendar.clicked.connect(self.onDateChanged)
|
||||
prev_btn = self.calendar.findChild(QToolButton, "qt_calendar_prevmonth")
|
||||
prev_btn.setIcon(Icon.Arrow_left_Icon)
|
||||
next_btn = self.calendar.findChild(QToolButton, "qt_calendar_nextmonth")
|
||||
next_btn.setIcon(Icon.Arrow_right_Icon)
|
||||
self.date_range = date_range
|
||||
if date_range:
|
||||
self.calendar.setDateRange(*date_range)
|
||||
# 从第一天开始,依次添加日期到列表,直到该月的最后一天
|
||||
current_date = date_range[1]
|
||||
while (current_date + timedelta(days=1)).month == date_range[1].month:
|
||||
current_date += timedelta(days=1)
|
||||
range_format = self.calendar.dateTextFormat(current_date)
|
||||
range_format.setForeground(Qt.gray)
|
||||
self.calendar.setDateTextFormat(current_date, range_format)
|
||||
# 从第一天开始,依次添加日期到列表,直到该月的最后一天
|
||||
current_date = date_range[0]
|
||||
while (current_date - timedelta(days=1)).month == date_range[0].month:
|
||||
current_date -= timedelta(days=1)
|
||||
range_format = self.calendar.dateTextFormat(current_date)
|
||||
range_format.setForeground(Qt.gray)
|
||||
self.calendar.setDateTextFormat(current_date, range_format)
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(self.calendar)
|
||||
self.setLayout(layout)
|
||||
|
||||
def set_start_date(self):
|
||||
if self.date_range:
|
||||
self.calendar.setCurrentPage(self.date_range[0].year, self.date_range[0].month)
|
||||
def set_end_date(self):
|
||||
if self.date_range:
|
||||
self.calendar.setCurrentPage(self.date_range[1].year, self.date_range[1].month)
|
||||
def onDateChanged(self):
|
||||
# 获取选择的日期
|
||||
selected_date = self.calendar.selectedDate()
|
||||
s_t = time.strptime(selected_date.toString("yyyy-MM-dd"), "%Y-%m-%d") # 返回元祖
|
||||
mkt = int(time.mktime(s_t))
|
||||
timestamp = mkt
|
||||
self.selected_date_signal.emit(timestamp)
|
||||
print("Selected Date:", selected_date.toString("yyyy-MM-dd"), timestamp)
|
||||
self.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
# 设置日期范围
|
||||
start_date = datetime(2024, 1, 5)
|
||||
end_date = datetime(2024, 1, 9)
|
||||
date_range = (start_date.date(), end_date.date())
|
||||
ex = CalendarDialog(date_range=date_range)
|
||||
ex.show()
|
||||
sys.exit(app.exec_())
|
||||
104
app/components/contact_info_ui.py
Normal file
104
app/components/contact_info_ui.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import sys
|
||||
|
||||
from PyQt5.Qt import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from .CAvatar import CAvatar
|
||||
|
||||
Stylesheet = """
|
||||
QWidget{
|
||||
background: rgb(238,244,249);
|
||||
}
|
||||
"""
|
||||
Stylesheet_hover = """
|
||||
QWidget,QLabel{
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
"""
|
||||
Stylesheet_clicked = """
|
||||
QWidget,QLabel{
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class QListWidgetItemWidget(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.is_selected = False
|
||||
|
||||
def leaveEvent(self, e): # 鼠标离开label
|
||||
if self.is_selected:
|
||||
return
|
||||
self.setStyleSheet(Stylesheet)
|
||||
|
||||
def enterEvent(self, e): # 鼠标移入label
|
||||
self.setStyleSheet(Stylesheet_hover)
|
||||
|
||||
|
||||
# 自定义的item 继承自QListWidgetItem
|
||||
class ContactQListWidgetItem(QListWidgetItem):
|
||||
def __init__(self, name, url, img_bytes=None):
|
||||
super().__init__()
|
||||
# 自定义item中的widget 用来显示自定义的内容
|
||||
self.widget = QListWidgetItemWidget()
|
||||
# 用来显示name
|
||||
self.nameLabel = QLabel(self.widget)
|
||||
self.nameLabel.setText(name)
|
||||
# 用来显示avator(图像)
|
||||
self.avatorLabel = CAvatar(parent=self.widget, shape=CAvatar.Rectangle, size=QSize(60, 60),
|
||||
url=url, img_bytes=img_bytes)
|
||||
# 设置布局用来对nameLabel和avatorLabel进行布局
|
||||
hbox = QHBoxLayout()
|
||||
hbox.addWidget(self.avatorLabel)
|
||||
hbox.addWidget(self.nameLabel)
|
||||
hbox.addStretch(1)
|
||||
# 设置widget的布局
|
||||
self.widget.setLayout(hbox)
|
||||
self.widget.setStyleSheet(Stylesheet)
|
||||
# 设置自定义的QListWidgetItem的sizeHint,不然无法显示
|
||||
self.setSizeHint(self.widget.sizeHint())
|
||||
|
||||
def select(self):
|
||||
"""
|
||||
设置选择后的事件
|
||||
@return:
|
||||
"""
|
||||
self.widget.is_selected = True
|
||||
self.widget.setStyleSheet(Stylesheet_clicked)
|
||||
|
||||
def dis_select(self):
|
||||
"""
|
||||
设置取消选择的事件
|
||||
@return:
|
||||
"""
|
||||
self.widget.is_selected = False
|
||||
self.widget.setStyleSheet(Stylesheet)
|
||||
|
||||
|
||||
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_())
|
||||
127
app/components/export_contact_item.py
Normal file
127
app/components/export_contact_item.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import sys
|
||||
|
||||
from PyQt5.Qt import *
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
try:
|
||||
from .CAvatar import CAvatar
|
||||
except:
|
||||
from CAvatar import CAvatar
|
||||
|
||||
Stylesheet = """
|
||||
QWidget{
|
||||
background: rgb(238,244,249);
|
||||
}
|
||||
"""
|
||||
Stylesheet_hover = """
|
||||
QWidget,QLabel{
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
"""
|
||||
Stylesheet_clicked = """
|
||||
QWidget,QLabel{
|
||||
background: rgb(230, 235, 240);
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class QListWidgetItemWidget(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.is_selected = False
|
||||
|
||||
def leaveEvent(self, e): # 鼠标离开label
|
||||
if self.is_selected:
|
||||
return
|
||||
self.setStyleSheet(Stylesheet)
|
||||
|
||||
def enterEvent(self, e): # 鼠标移入label
|
||||
self.setStyleSheet(Stylesheet_hover)
|
||||
|
||||
|
||||
# 自定义的item 继承自QListWidgetItem
|
||||
class ContactQListWidgetItem(QListWidgetItem):
|
||||
def __init__(self, name, url, img_bytes=None):
|
||||
super().__init__()
|
||||
self.is_select = False
|
||||
# 自定义item中的widget 用来显示自定义的内容
|
||||
self.widget = QListWidgetItemWidget()
|
||||
# 用来显示name
|
||||
self.nameLabel = QLabel(self.widget)
|
||||
self.nameLabel.setText(name)
|
||||
# 用来显示avator(图像)
|
||||
self.avatorLabel = CAvatar(parent=self.widget, shape=CAvatar.Rectangle, size=QSize(30, 30),
|
||||
url=url, img_bytes=img_bytes)
|
||||
# 设置布局用来对nameLabel和avatorLabel进行布局
|
||||
hbox = QHBoxLayout(self.widget)
|
||||
self.checkBox = QCheckBox(self.widget)
|
||||
self.checkBox.clicked.connect(self.select)
|
||||
hbox.addWidget(self.checkBox)
|
||||
hbox.addWidget(self.avatorLabel)
|
||||
hbox.addWidget(self.nameLabel)
|
||||
hbox.addStretch(1)
|
||||
# 设置widget的布局
|
||||
self.widget.setLayout(hbox)
|
||||
self.widget.setStyleSheet(Stylesheet)
|
||||
# 设置自定义的QListWidgetItem的sizeHint,不然无法显示
|
||||
self.setSizeHint(self.widget.sizeHint())
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
|
||||
self.widget.setSizePolicy(sizePolicy)
|
||||
|
||||
def select(self):
|
||||
"""
|
||||
设置选择后的事件
|
||||
@return:
|
||||
"""
|
||||
self.widget.is_selected = True
|
||||
self.is_select = not self.is_select
|
||||
# print('选择',self.is_select)
|
||||
self.checkBox.setChecked(self.is_select)
|
||||
# self.widget.setStyleSheet(Stylesheet_clicked)
|
||||
|
||||
def force_select(self):
|
||||
self.is_select = True
|
||||
self.checkBox.setChecked(self.is_select)
|
||||
|
||||
def force_dis_select(self):
|
||||
self.is_select = False
|
||||
self.checkBox.setChecked(self.is_select)
|
||||
|
||||
def dis_select(self):
|
||||
"""
|
||||
设置取消选择的事件
|
||||
@return:
|
||||
"""
|
||||
self.widget.is_selected = False
|
||||
self.widget.setStyleSheet(Stylesheet)
|
||||
|
||||
|
||||
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: item.select())
|
||||
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
39
app/components/prompt_bar.py
Normal file
39
app/components/prompt_bar.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
|
||||
class PromptBar(QLabel):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
def paintEvent(self, e): # 绘图事件
|
||||
qp = QPainter()
|
||||
qp.begin(self)
|
||||
self.drawRectangles1(qp) # 绘制线条矩形
|
||||
self.drawRectangles2(qp) # 绘制填充矩形
|
||||
self.drawRectangles3(qp) # 绘制线条+填充矩形
|
||||
self.drawRectangles4(qp) # 绘制线条矩形2
|
||||
qp.end()
|
||||
|
||||
def drawRectangles1(self, qp): # 绘制填充矩形
|
||||
qp.setPen(QPen(Qt.black, 2, Qt.SolidLine)) # 颜色、线宽、线性
|
||||
qp.drawRect(*self.data)
|
||||
|
||||
def drawRectangles2(self, qp): # 绘制填充矩形
|
||||
qp.setPen(QPen(Qt.black, 2, Qt.NoPen))
|
||||
qp.setBrush(QColor(200, 0, 0))
|
||||
qp.drawRect(220, 15, 200, 100)
|
||||
|
||||
def drawRectangles3(self, qp): # 绘制线条+填充矩形
|
||||
qp.setPen(QPen(Qt.black, 2, Qt.SolidLine))
|
||||
qp.setBrush(QColor(200, 0, 0))
|
||||
qp.drawRect(430, 15, 200, 100)
|
||||
|
||||
def drawRectangles4(self, qp): # 绘制线条矩形2
|
||||
path = QtGui.QPainterPath()
|
||||
qp.setPen(QPen(Qt.blue, 2, Qt.SolidLine))
|
||||
qp.setBrush(QColor(0, 0, 0, 0)) # 设置画刷颜色透明
|
||||
path.addRect(100, 200, 200, 100)
|
||||
qp.drawPath(path)
|
||||
48
app/components/scroll_bar.py
Normal file
48
app/components/scroll_bar.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from PyQt5.QtWidgets import QScrollBar
|
||||
|
||||
|
||||
class ScrollBar(QScrollBar):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setStyleSheet(
|
||||
'''
|
||||
QScrollBar:vertical {
|
||||
border-width: 0px;
|
||||
border: none;
|
||||
background:rgba(133, 135, 138, 0);
|
||||
width:4px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
}
|
||||
QScrollBar::handle:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgb(133, 135, 138), stop: 0.5 rgb(133, 135, 138), stop:1 rgb(133, 135, 138));
|
||||
min-height: 20px;
|
||||
max-height: 20px;
|
||||
margin: 0 0px 0 0px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
QScrollBar::add-line:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
|
||||
height: 0px;
|
||||
border: none;
|
||||
subcontrol-position: bottom;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
QScrollBar::sub-line:vertical {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop: 0 rgba(133, 135, 138, 0), stop: 0.5 rgba(133, 135, 138, 0), stop:1 rgba(133, 135, 138, 0));
|
||||
height: 0 px;
|
||||
border: none;
|
||||
subcontrol-position: top;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
QScrollBar::sub-page:vertical {
|
||||
background: rgba(133, 135, 138, 0);
|
||||
}
|
||||
|
||||
QScrollBar::add-page:vertical {
|
||||
background: rgba(133, 135, 138, 0);
|
||||
}
|
||||
'''
|
||||
)
|
||||
Reference in New Issue
Block a user