select让文字居中:有解

本文详细介绍了如何使用HTML和CSS实现一个简单的下拉选择器,并通过JavaScript动态更新其样式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style>

        .ui-select {
            text-align: center;
            /* 加border只是为了看到边框*/
            border:solid 1px;
        }
        .ui-select select {
            position: absolute;
            left: 0px;
            top: 0px;
            width: 100%;
            height: 3em;
            opacity: 0;
        }

    </style>
</head>
<body>
<div class="ui-select">
    <span>The 1st Option</span>
    <select>
        <option value="1">The 1st Option</option>
        <option value="2">The 2nd Option</option>
        <option value="3">The 3rd Option</option>
        <option value="4">The 4th Option</option>
    </select>
</div>
</body>
</html>



                
. main.py Python 复制 # 导入必要的模块 import sys from PyQt5.QtWidgets import QApplication from image_editor import ImageEditor def main(): """主函数,创建并启动应用程序""" app = QApplication(sys.argv) # 创建应用程序实例 editor = ImageEditor() # 创建图像编辑器实例 editor.show() # 显示主窗口 sys.exit(app.exec_()) # 运行应用程序 if __name__ == "__main__": main() # 程序入口点 2. image_editor.py Python 复制 # 导入必要的模块 import cv2 import numpy as np import os from PyQt5.QtWidgets import QMainWindow, QLabel, QFileDialog, QMessageBox from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtCore import Qt from tools.brightness_contrast import BrightnessContrastTool from tools.blur import BlurTool from tools.sharpen import SharpenTool from tools.crop import CropTool from tools.rotate import RotateTool from tools.scale import ScaleTool from tools.flip import FlipTool from tools.text import TextTool from tools.sticker import StickerTool class ImageEditor(QMainWindow): """图像编辑器主类""" def __init__(self): super().__init__() self.setWindowTitle("图像编辑器") # 设置窗口标题 self.setGeometry(100, 100, 800, 600) # 设置窗口位置和大小 self.image = None # 当前图像 self.history = [] # 操作历史栈 self.future = [] # 未来操作栈 self.tools = {} # 初始化工具字典 self.init_tools() # 初始化工具 self.init_ui() # 初始化用户界面 def init_ui(self): """初始化用户界面""" # 创建显示图像的标签,居中对齐 self.canvas = QLabel(self) self.canvas.setAlignment(Qt.AlignCenter) # 设置背景颜色为透明 self.canvas.setStyleSheet("background-color: rgba(0, 0, 0, 0);") # 将标签设为中心部件 self.setCentralWidget(self.canvas) # 创建菜单栏 self.create_menu() def create_menu(self): """创建菜单栏""" # 获取菜单栏 menu_bar = self.menuBar() # 创建文件菜单 file_menu = menu_bar.addMenu("文件") # 创建并添加打开菜单项 open_action = QAction("打开", self) open_action.triggered.connect(self.open_image) file_menu.addAction(open_action) # 创建并添加保存菜单项 save_action = QAction("保存", self) save_action.triggered.connect(self.save_image) file_menu.addAction(save_action) # 创建编辑菜单 edit_menu = menu_bar.addMenu("编辑") # 创建并添加撤销菜单项 undo_action = QAction("撤销", self) undo_action.triggered.connect(self.undo) edit_menu.addAction(undo_action) # 创建并添加重做菜单项 redo_action = QAction("重做", self) redo_action.triggered.connect(self.redo) edit_menu.addAction(redo_action) # 创建并添加重置菜单项 reset_action = QAction("重置", self) reset_action.triggered.connect(self.reset) edit_menu.addAction(reset_action) # 创建调整菜单 adjust_menu = menu_bar.addMenu("调整") # 创建并添加亮度对比度菜单项 brightness_contrast_action = QAction("亮度对比度", self) brightness_contrast_action.triggered.connect(self.show_brightness_contrast_dialog) adjust_menu.addAction(brightness_contrast_action) # 创建并添加模糊菜单项 blur_action = QAction("模糊", self) blur_action.triggered.connect(self.show_blur_dialog) adjust_menu.addAction(blur_action) # 创建并添加锐化菜单项 sharpen_action = QAction("锐化", self) sharpen_action.triggered.connect(self.show_sharpen_dialog) adjust_menu.addAction(sharpen_action) # 创建操作菜单 operation_menu = menu_bar.addMenu("操作") # 创建并添加裁剪菜单项 crop_action = QAction("裁剪", self) crop_action.triggered.connect(self.show_crop_dialog) operation_menu.addAction(crop_action) # 创建并添加旋转菜单项 rotate_action = QAction("旋转", self) rotate_action.triggered.connect(self.show_rotate_dialog) operation_menu.addAction(rotate_action) # 创建并添加缩放菜单项 scale_action = QAction("缩放", self) scale_action.triggered.connect(self.show_scale_dialog) operation_menu.addAction(scale_action) # 创建并添加翻转菜单项 flip_action = QAction("翻转", self) flip_action.triggered.connect(self.show_flip_dialog) operation_menu.addAction(flip_action) # 创建添加菜单 add_menu = menu_bar.addMenu("添加") # 创建并添加文字菜单项 text_action = QAction("文字", self) text_action.triggered.connect(self.show_text_dialog) add_menu.addAction(text_action) # 创建并添加贴纸菜单项 sticker_action = QAction("贴纸", self) sticker_action.triggered.connect(self.show_sticker_dialog) add_menu.addAction(sticker_action) def init_tools(self): """初始化工具""" self.tools = { "brightness_contrast": BrightnessContrastTool(self), "blur": BlurTool(self), "sharpen": SharpenTool(self), "crop": CropTool(self), "rotate": RotateTool(self), "scale": ScaleTool(self), "flip": FlipTool(self), "text": TextTool(self), "sticker": StickerTool(self) } def show_brightness_contrast_dialog(self): """显示亮度对比度对话框""" self.tools["brightness_contrast"].show_dialog() def show_blur_dialog(self): """显示模糊对话框""" self.tools["blur"].show_dialog() def show_sharpen_dialog(self): """显示锐化对话框""" self.tools["sharpen"].show_dialog() def show_crop_dialog(self): """显示裁剪对话框""" self.tools["crop"].show_dialog() def show_rotate_dialog(self): """显示旋转对话框""" self.tools["rotate"].show_dialog() def show_scale_dialog(self): """显示缩放对话框""" self.tools["scale"].show_dialog() def show_flip_dialog(self): """显示翻转对话框""" self.tools["flip"].show_dialog() def show_text_dialog(self): """显示文字对话框""" self.tools["text"].show_dialog() def show_sticker_dialog(self): """显示贴纸对话框""" self.tools["sticker"].show_dialog() def open_image(self): """打开图像文件""" # 打开文件对话框,获取选定的文件路径 file_path, _ = QFileDialog.getOpenFileName( self, "打开图像", "", "图像文件 (*.png *.jpg *.jpeg *.bmp)" ) if file_path: # 检查文件是否存在 if not os.path.exists(file_path): QMessageBox.warning(self, "错误", "文件不存在!") return # 如果图像未初始化,创建一个透明背景 if self.image is None: self.image = np.ones((800, 600, 4), dtype=np.uint8) * 255 self.image[:, :, 3] = 0 # 设置透明度通道为 0(完全透明) # 读取图像 img = cv2.imread(file_path) if img is None: QMessageBox.warning(self, "错误", "无法读取图像文件!") return # 如果是灰度图像,转换为彩色 if len(img.shape) == 2: img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 如果图像有 alpha 通道,合并到当前图像 if img.shape[2] == 4: # 将新图像融合到透明背景 self.image = cv2.add(self.image, img) else: # 否则,添加 alpha 通道并融合 img_with_alpha = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA) self.image = cv2.add(self.image, img_with_alpha) # 将当前图像压入历史栈 self.push_history() # 更新显示 self.update_canvas() def save_image(self): """保存图像""" if self.image is None: return # 如果没有图像,则返回 # 打开保存文件对话框,获取保存的文件路径 file_path, _ = QFileDialog.getSaveFileName( self, "保存图像", "", "图像文件 (*.png *.jpg *.jpeg *.bmp)" ) if file_path: # 保存图像 cv2.imwrite(file_path, self.image) def push_history(self): """将当前图像状态压入历史栈""" if self.image is not None: # 复制当前图像并压入历史栈 self.history.append(self.image.copy()) # 清空未来栈 self.future = [] def undo(self): """撤销操作""" if len(self.history) > 1: # 如果历史栈中有多个状态 # 将当前图像压入未来栈 self.future.append(self.image.copy()) # 弹出历史栈的顶部 self.image = self.history.pop() # 更新显示 self.update_canvas() def redo(self): """重做操作""" if len(self.future) > 0: # 如果未来栈中有状态 # 将当前图像压入历史栈 self.history.append(self.image.copy()) # 弹出未来栈的顶部 self.image = self.future.pop() # 更新显示 self.update_canvas() def reset(self): """重置图像""" if len(self.history) > 0: # 如果历史栈中有初始状态 # 将当前图像压入未来栈 if len(self.history) > 1: self.future.append(self.image.copy()) # 重置历史栈为初始状态 self.history = self.history[:1] # 重置当前图像为初始状态 self.image = self.history[0].copy() # 更新显示 self.update_canvas() def update_canvas(self): """更新画布显示""" if self.image is not None: # 将图像从 BGRA 转换为 ARGB(Qt 使用 ARGB 格式) argb_image = cv2.cvtColor(self.image, cv2.COLOR_BGRA2RGBA) # 获取图像高度和宽度 height, width, channel = argb_image.shape # 计算每行的字节数 bytes_per_line = channel * width # 创建 QImage 对象 q_image = QImage( argb_image.data, width, height, bytes_per_line, QImage.Format_ARGB32 ) # 创建 QPixmap 对象 pixmap = QPixmap.fromImage(q_image) # 设置标签的图片 self.canvas.setPixmap(pixmap) # 调整标签大小以适应图片 self.canvas.setFixedSize(width, height) 3. tools/__init__.py Python 复制 # 这个文件用于将 tools 包标记为 Python 包 4. tools/brightness_contrast.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QSlider, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit from PyQt5.QtCore import Qt class BrightnessContrastDialog(QDialog): """亮度对比度对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("亮度对比度调节") self.brightness_value = 0 self.contrast_value = 0 self.init_ui() def init_ui(self): """初始化用户界面""" # 创建亮度滑动条,水平方向 self.slider_brightness = QSlider(Qt.Horizontal) self.slider_brightness.setRange(-100, 100) self.slider_brightness.setValue(0) self.label_brightness = QLabel("亮度: 0") # 创建对比度滑动条,水平方向 self.slider_contrast = QSlider(Qt.Horizontal) self.slider_contrast.setRange(-100, 100) self.slider_contrast.setValue(0) self.label_contrast = QLabel("对比度: 0") # 创建用于输入亮度值的文本框 self.edit_brightness = QLineEdit("0") self.edit_brightness.setFixedWidth(50) # 创建用于输入对比度值的文本框 self.edit_contrast = QLineEdit("0") self.edit_contrast.setFixedWidth(50) # 将滑动条的值改变信号连接到处理函数 self.slider_brightness.valueChanged.connect(self.on_slider_brightness) # 将文本框的文本改变信号连接到处理函数 self.edit_brightness.textChanged.connect(self.on_edit_brightness) # 将滑动条的值改变信号连接到处理函数 self.slider_contrast.valueChanged.connect(self.on_slider_contrast) # 将文本框的文本改变信号连接到处理函数 self.edit_contrast.textChanged.connect(self.on_edit_contrast) # 创建垂直布局管理器 layout = QVBoxLayout() # 添加亮度标签 layout.addWidget(QLabel("亮度:")) # 创建水平布局管理器 h_layout = QHBoxLayout() h_layout.addWidget(self.slider_brightness) h_layout.addWidget(self.label_brightness) h_layout.addWidget(self.edit_brightness) layout.addLayout(h_layout) # 添加对比度标签 layout.addWidget(QLabel("对比度:")) # 创建水平布局管理器 h_layout = QHBoxLayout() h_layout.addWidget(self.slider_contrast) h_layout.addWidget(self.label_contrast) h_layout.addWidget(self.edit_contrast) layout.addLayout(h_layout) # 创建确定按钮 btn_ok = QPushButton("确定") btn_ok.clicked.connect(self.accept) # 创建取消按钮 btn_cancel = QPushButton("取消") btn_cancel.clicked.connect(self.reject) # 创建按钮布局管理器 btn_layout = QHBoxLayout() btn_layout.addWidget(btn_ok) btn_layout.addWidget(btn_cancel) # 将按钮布局添加到主布局 layout.addLayout(btn_layout) # 设置对话框的布局 self.setLayout(layout) def on_slider_brightness(self, value): """处理亮度滑动条值改变事件""" self.brightness_value = value self.label_brightness.setText(f"亮度: {value}") self.edit_brightness.setText(str(value)) def on_slider_contrast(self, value): """处理对比度滑动条值改变事件""" self.contrast_value = value self.label_contrast.setText(f"对比度: {value}") self.edit_contrast.setText(str(value)) def on_edit_brightness(self, text): """处理亮度文本框文本改变事件""" try: value = int(text) if value < -100: value = -100 elif value > 100: value = 100 self.brightness_value = value self.slider_brightness.setValue(value) self.label_brightness.setText(f"亮度: {value}") except ValueError: pass def on_edit_contrast(self, text): """处理对比度文本框文本改变事件""" try: value = int(text) if value < -100: value = -100 elif value > 100: value = 100 self.contrast_value = value self.slider_contrast.setValue(value) self.label_contrast.setText(f"对比度: {value}") except ValueError: pass def get_values(self): """获取当前的亮度和对比度值""" return self.brightness_value, self.contrast_value def accept(self): """处理确定按钮点击事件""" # 获取亮度和对比度值 brightness, contrast = self.get_values() # 调整图像的亮度和对比度 self.editor.image = cv2.convertScaleAbs(self.editor.image, alpha=1 + contrast/100.0, beta=brightness) # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class BrightnessContrastTool: """亮度对比度工具类""" def __init__(self, editor): self.editor = editor self.dialog = BrightnessContrastDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 5. tools/blur.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QSlider, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit from PyQt5.QtCore import Qt class BlurDialog(QDialog): """模糊对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("模糊滤镜") self.blur_value = 1 self.init_ui() def init_ui(self): """初始化用户界面""" # 创建模糊滑动条,水平方向 self.slider_blur = QSlider(Qt.Horizontal) self.slider_blur.setRange(1, 25) self.slider_blur.setValue(1) self.label_blur = QLabel("模糊半径: 1") # 创建用于输入模糊值的文本框 self.edit_blur = QLineEdit("1") self.edit_blur.setFixedWidth(50) # 将滑动条的值改变信号连接到处理函数 self.slider_blur.valueChanged.connect(self.on_slider_blur) # 将文本框的文本改变信号连接到处理函数 self.edit_blur.textChanged.connect(self.on_edit_blur) # 创建垂直布局管理器 layout = QVBoxLayout() # 添加模糊标签 layout.addWidget(QLabel("模糊半径:")) # 创建水平布局管理器 h_layout = QHBoxLayout() h_layout.addWidget(self.slider_blur) h_layout.addWidget(self.label_blur) h_layout.addWidget(self.edit_blur) layout.addLayout(h_layout) # 创建确定按钮 btn_ok = QPushButton("确定") btn_ok.clicked.connect(self.accept) # 创建取消按钮 btn_cancel = QPushButton("取消") btn_cancel.clicked.connect(self.reject) # 创建按钮布局管理器 btn_layout = QHBoxLayout() btn_layout.addWidget(btn_ok) btn_layout.addWidget(btn_cancel) # 将按钮布局添加到主布局 layout.addLayout(btn_layout) # 设置对话框的布局 self.setLayout(layout) def on_slider_blur(self, value): """处理模糊滑动条值改变事件""" self.blur_value = value self.label_blur.setText(f"模糊半径: {value}") self.edit_blur.setText(str(value)) def on_edit_blur(self, text): """处理模糊文本框文本改变事件""" try: value = int(text) if value < 1: value = 1 elif value > 25: value = 25 self.blur_value = value self.slider_blur.setValue(value) self.label_blur.setText(f"模糊半径: {value}") except ValueError: pass def get_value(self): """获取当前的模糊值""" return self.blur_value def accept(self): """处理确定按钮点击事件""" # 获取模糊值 blur_value = self.get_value() # 创建模糊核 kernel_size = (blur_value * 2 + 1, blur_value * 2 + 1) # 应用模糊滤镜 self.editor.image = cv2.GaussianBlur(self.editor.image, kernel_size, 0) # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class BlurTool: """模糊工具类""" def __init__(self, editor): self.editor = editor self.dialog = BlurDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 6. tools/sharpen.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QSlider, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit from PyQt5.QtCore import Qt class SharpenDialog(QDialog): """锐化对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("锐化滤镜") self.sharpen_value = 1 self.init_ui() def init_ui(self): """初始化用户界面""" # 创建锐化滑动条,水平方向 self.slider_sharpen = QSlider(Qt.Horizontal) self.slider_sharpen.setRange(1, 10) self.slider_sharpen.setValue(1) self.label_sharpen = QLabel("锐化强度: 1") # 创建用于输入锐化值的文本框 self.edit_sharpen = QLineEdit("1") self.edit_sharpen.setFixedWidth(50) # 将滑动条的值改变信号连接到处理函数 self.slider_sharpen.valueChanged.connect(self.on_slider_sharpen) # 将文本框的文本改变信号连接到处理函数 self.edit_sharpen.textChanged.connect(self.on_edit_sharpen) # 创建垂直布局管理器 layout = QVBoxLayout() # 添加锐化标签 layout.addWidget(QLabel("锐化强度:")) # 创建水平布局管理器 h_layout = QHBoxLayout() h_layout.addWidget(self.slider_sharpen) h_layout.addWidget(self.label_sharpen) h_layout.addWidget(self.edit_sharpen) layout.addLayout(h_layout) # 创建确定按钮 btn_ok = QPushButton("确定") btn_ok.clicked.connect(self.accept) # 创建取消按钮 btn_cancel = QPushButton("取消") btn_cancel.clicked.connect(self.reject) # 创建按钮布局管理器 btn_layout = QHBoxLayout() btn_layout.addWidget(btn_ok) btn_layout.addWidget(btn_cancel) # 将按钮布局添加到主布局 layout.addLayout(btn_layout) # 设置对话框的布局 self.setLayout(layout) def on_slider_sharpen(self, value): """处理锐化滑动条值改变事件""" self.sharpen_value = value self.label_sharpen.setText(f"锐化强度: {value}") self.edit_sharpen.setText(str(value)) def on_edit_sharpen(self, text): """处理锐化文本框文本改变事件""" try: value = int(text) if value < 1: value = 1 elif value > 10: value = 10 self.sharpen_value = value self.slider_sharpen.setValue(value) self.label_sharpen.setText(f"锐化强度: {value}") except ValueError: pass def get_value(self): """获取当前的锐化值""" return self.sharpen_value def accept(self): """处理确定按钮点击事件""" # 获取锐化值 sharpen_value = self.get_value() # 创建锐化核 kernel = np.array([[-1, -1, -1], [-1, 5 + sharpen_value, -1], [-1, -1, -1]], dtype=np.float32) # 应用锐化滤镜 self.editor.image = cv2.filter2D(self.editor.image, -1, kernel) # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class SharpenTool: """锐化工具类""" def __init__(self, editor): self.editor = editor self.dialog = SharpenDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 7. tools/crop.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit from PyQt5.QtCore import Qt class CropDialog(QDialog): """裁剪对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("裁剪图像") self.x = 0 self.y = 0 self.width = 100 self.height = 100 self.init_ui() def init_ui(self): """初始化用户界面""" # 获取图像尺寸 if self.editor.image is not None: height, width, _ = self.editor.image.shape self.width = width self.height = height # 创建 X 坐标输入框和标签 self.label_x = QLabel("X:") self.edit_x = QLineEdit("0") self.edit_x.setFixedWidth(60) # 创建 Y 坐标输入框和标签 self.label_y = QLabel("Y:") self.edit_y = QLineEdit("0") self.edit_y.setFixedWidth(60) # 创建宽度输入框和标签 self.label_width = QLabel("宽度:") self.edit_width = QLineEdit(str(self.width)) self.edit_width.setFixedWidth(60) # 创建高度输入框和标签 self.label_height = QLabel("高度:") self.edit_height = QLineEdit(str(self.height)) self.edit_height.setFixedWidth(60) # 创建垂直布局管理器 layout = QVBoxLayout() # 添加 X 坐标输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_x) h_layout.addWidget(self.edit_x) layout.addLayout(h_layout) # 添加 Y 坐标输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_y) h_layout.addWidget(self.edit_y) layout.addLayout(h_layout) # 添加宽度输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_width) h_layout.addWidget(self.edit_width) layout.addLayout(h_layout) # 添加高度输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_height) h_layout.addWidget(self.edit_height) layout.addLayout(h_layout) # 创建确定按钮 btn_ok = QPushButton("确定") btn_ok.clicked.connect(self.accept) # 创建取消按钮 btn_cancel = QPushButton("取消") btn_cancel.clicked.connect(self.reject) # 创建按钮布局管理器 btn_layout = QHBoxLayout() btn_layout.addWidget(btn_ok) btn_layout.addWidget(btn_cancel) # 将按钮布局添加到主布局 layout.addLayout(btn_layout) # 设置对话框的布局 self.setLayout(layout) def get_values(self): """获取当前的裁剪参数""" try: x = int(self.edit_x.text()) y = int(self.edit_y.text()) width = int(self.edit_width.text()) height = int(self.edit_height.text()) return x, y, width, height except ValueError: return 0, 0, 100, 100 def accept(self): """处理确定按钮点击事件""" # 获取裁剪参数 x, y, width, height = self.get_values() # 确保参数在有效范围内 if self.editor.image is not None: img_height, img_width, _ = self.editor.image.shape x = max(0, min(x, img_width - 1)) y = max(0, min(y, img_height - 1)) width = max(1, min(width, img_width - x)) height = max(1, min(height, img_height - y)) # 裁剪图像 self.editor.image = self.editor.image[y:y+height, x:x+width] # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class CropTool: """裁剪工具类""" def __init__(self, editor): self.editor = editor self.dialog = CropDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.init_ui() # 重新初始化 UI 以获取最新图像尺寸 self.dialog.show() 8. tools/rotate.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QSlider, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit from PyQt5.QtCore import Qt class RotateDialog(QDialog): """旋转对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("旋转图像") self.rotate_value = 0 self.init_ui() def init_ui(self): """初始化用户界面""" # 创建旋转滑动条,水平方向 self.slider_rotate = QSlider(Qt.Horizontal) self.slider_rotate.setRange(-180, 180) self.slider_rotate.setValue(0) self.label_rotate = QLabel("旋转角度: 0") # 创建用于输入旋转角度的文本框 self.edit_rotate = QLineEdit("0") self.edit_rotate.setFixedWidth(50) # 将滑动条的值改变信号连接到处理函数 self.slider_rotate.valueChanged.connect(self.on_slider_rotate) # 将文本框的文本改变信号连接到处理函数 self.edit_rotate.textChanged.connect(self.on_edit_rotate) # 创建垂直布局管理器 layout = QVBoxLayout() # 添加旋转标签 layout.addWidget(QLabel("旋转角度:")) # 创建水平布局管理器 h_layout = QHBoxLayout() h_layout.addWidget(self.slider_rotate) h_layout.addWidget(self.label_rotate) h_layout.addWidget(self.edit_rotate) layout.addLayout(h_layout) # 创建确定按钮 btn_ok = QPushButton("确定") btn_ok.clicked.connect(self.accept) # 创建取消按钮 btn_cancel = QPushButton("取消") btn_cancel.clicked.connect(self.reject) # 创建按钮布局管理器 btn_layout = QHBoxLayout() btn_layout.addWidget(btn_ok) btn_layout.addWidget(btn_cancel) # 将按钮布局添加到主布局 layout.addLayout(btn_layout) # 设置对话框的布局 self.setLayout(layout) def on_slider_rotate(self, value): """处理旋转滑动条值改变事件""" self.rotate_value = value self.label_rotate.setText(f"旋转角度: {value}") self.edit_rotate.setText(str(value)) def on_edit_rotate(self, text): """处理旋转文本框文本改变事件""" try: value = int(text) if value < -180: value = -180 elif value > 180: value = 180 self.rotate_value = value self.slider_rotate.setValue(value) self.label_rotate.setText(f"旋转角度: {value}") except ValueError: pass def get_value(self): """获取当前的旋转角度""" return self.rotate_value def accept(self): """处理确定按钮点击事件""" # 获取旋转角度 angle = self.get_value() # 获取图像中心 if self.editor.image is not None: (h, w) = self.editor.image.shape[:2] (cX, cY) = (w // 2, h // 2) # 创建旋转矩阵 M = cv2.getRotationMatrix2D((cX, cY), angle, 1.0) # 应用旋转 self.editor.image = cv2.warpAffine(self.editor.image, M, (w, h)) # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class RotateTool: """旋转工具类""" def __init__(self, editor): self.editor = editor self.dialog = RotateDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 9. tools/scale.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QSlider, QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit from PyQt5.QtCore import Qt class ScaleDialog(QDialog): """缩放对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("缩放图像") self.scale_value = 100 self.init_ui() def init_ui(self): """初始化用户界面""" # 创建缩放滑动条,水平方向 self.slider_scale = QSlider(Qt.Horizontal) self.slider_scale.setRange(10, 300) self.slider_scale.setValue(100) self.label_scale = QLabel("缩放比例: 100%") # 创建用于输入缩放比例的文本框 self.edit_scale = QLineEdit("100") self.edit_scale.setFixedWidth(50) # 将滑动条的值改变信号连接到处理函数 self.slider_scale.valueChanged.connect(self.on_slider_scale) # 将文本框的文本改变信号连接到处理函数 self.edit_scale.textChanged.connect(self.on_edit_scale) # 创建垂直布局管理器 layout = QVBoxLayout() # 添加缩放标签 layout.addWidget(QLabel("缩放比例:")) # 创建水平布局管理器 h_layout = QHBoxLayout() h_layout.addWidget(self.slider_scale) h_layout.addWidget(self.label_scale) h_layout.addWidget(self.edit_scale) layout.addLayout(h_layout) # 创建确定按钮 btn_ok = QPushButton("确定") btn_ok.clicked.connect(self.accept) # 创建取消按钮 btn_cancel = QPushButton("取消") btn_cancel.clicked.connect(self.reject) # 创建按钮布局管理器 btn_layout = QHBoxLayout() btn_layout.addWidget(btn_ok) btn_layout.addWidget(btn_cancel) # 将按钮布局添加到主布局 layout.addLayout(btn_layout) # 设置对话框的布局 self.setLayout(layout) def on_slider_scale(self, value): """处理缩放滑动条值改变事件""" self.scale_value = value self.label_scale.setText(f"缩放比例: {value}%") self.edit_scale.setText(str(value)) def on_edit_scale(self, text): """处理缩放文本框文本改变事件""" try: value = int(text) if value < 10: value = 10 elif value > 300: value = 300 self.scale_value = value self.slider_scale.setValue(value) self.label_scale.setText(f"缩放比例: {value}%") except ValueError: pass def get_value(self): """获取当前的缩放比例""" return self.scale_value def accept(self): """处理确定按钮点击事件""" # 获取缩放比例 scale = self.get_value() / 100.0 # 缩放图像 if self.editor.image is not None: new_width = int(self.editor.image.shape[1] * scale) new_height = int(self.editor.image.shape[0] * scale) self.editor.image = cv2.resize(self.editor.image, (new_width, new_height)) # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class ScaleTool: """缩放工具类""" def __init__(self, editor): self.editor = editor self.dialog = ScaleDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 10. tools/flip.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QVBoxLayout, QPushButton class FlipDialog(QDialog): """翻转对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("翻转图像") self.init_ui() def init_ui(self): """初始化用户界面""" # 创建按钮布局 btn_layout = QVBoxLayout() # 创建水平翻转按钮 btn_horizontal = QPushButton("水平翻转") btn_horizontal.clicked.connect(lambda: self.flip(1)) btn_layout.addWidget(btn_horizontal) # 创建垂直翻转按钮 btn_vertical = QPushButton("垂直翻转") btn_vertical.clicked.connect(lambda: self.flip(0)) btn_layout.addWidget(btn_vertical) # 创建水平+垂直翻转按钮 btn_both = QPushButton("水平+垂直翻转") btn_both.clicked.connect(lambda: self.flip(-1)) btn_layout.addWidget(btn_both) # 创建取消按钮 btn_cancel = QPushButton("取消") btn_cancel.clicked.connect(self.reject) btn_layout.addWidget(btn_cancel) # 设置对话框的布局 self.setLayout(btn_layout) def flip(self, code): """执行翻转操作""" # 翻转图像 if self.editor.image is not None: self.editor.image = cv2.flip(self.editor.image, code) # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() self.accept() class FlipTool: """翻转工具类""" def __init__(self, editor): self.editor = editor self.dialog = FlipDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 11. tools/text.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, QFontDialog from PyQt5.QtCore import Qt class TextDialog(QDialog): """文字对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("添加文字") self.text = "" self.x = 50 self.y = 50 self.font = "" self.color = (255, 255, 255) self.size = 1 self.init_ui() def init_ui(self): """初始化用户界面""" # 创建文字输入框和标签 self.label_text = QLabel("文字:") self.edit_text = QLineEdit() # 创建 X 坐标输入框和标签 self.label_x = QLabel("X:") self.edit_x = QLineEdit("50") self.edit_x.setFixedWidth(60) # 创建 Y 坐标输入框和标签 self.label_y = QLabel("Y:") self.edit_y = QLineEdit("50") self.edit_y.setFixedWidth(60) # 创建字体按钮 self.btn_font = QPushButton("选择字体") self.btn_font.clicked.connect(self.choose_font) # 创建颜色按钮 self.btn_color = QPushButton("选择颜色") self.btn_color.clicked.connect(self.choose_color) # 创建确定和取消按钮 self.btn_ok = QPushButton("确定") self.btn_ok.clicked.connect(self.accept) self.btn_cancel = QPushButton("取消") self.btn_cancel.clicked.connect(self.reject) # 创建布局 layout = QVBoxLayout() # 添加文字输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_text) h_layout.addWidget(self.edit_text) layout.addLayout(h_layout) # 添加 X 坐标输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_x) h_layout.addWidget(self.edit_x) layout.addLayout(h_layout) # 添加 Y 坐标输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_y) h_layout.addWidget(self.edit_y) layout.addLayout(h_layout) # 添加字体和颜色选择按钮 h_layout = QHBoxLayout() h_layout.addWidget(self.btn_font) h_layout.addWidget(self.btn_color) layout.addLayout(h_layout) # 添加确定和取消按钮 h_layout = QHBoxLayout() h_layout.addWidget(self.btn_ok) h_layout.addWidget(self.btn_cancel) layout.addLayout(h_layout) # 设置对话框的布局 self.setLayout(layout) def choose_font(self): """选择字体""" font, ok = QFontDialog.getFont() if ok: self.font = font.family() self.size = font.pointSizeF() def choose_color(self): """选择颜色""" # 这里简化处理,实际应用中应使用 QColorDialog self.color = (255, 0, 0) # 默认红色 def get_values(self): """获取当前的文字参数""" self.text = self.edit_text.text() try: self.x = int(self.edit_x.text()) self.y = int(self.edit_y.text()) except ValueError: self.x = 50 self.y = 50 return self.text, self.x, self.y, self.font, self.color, self.size def accept(self): """处理确定按钮点击事件""" # 获取文字参数 text, x, y, font, color, size = self.get_values() # 添加文字 if self.editor.image is not None and text: # 设置默认字体 if not font: font = cv2.FONT_HERSHEY_SIMPLEX else: # 尝试匹配字体,如果失败则使用默认字体 try: font = eval(f"cv2.FONT_{font.upper()}") except AttributeError: font = cv2.FONT_HERSHEY_SIMPLEX # 将颜色从 RGB 转换为 BGR bgr_color = (color[2], color[1], color[0]) # 添加文字 cv2.putText(self.editor.image, text, (x, y), font, size, bgr_color, 2) # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class TextTool: """文字工具类""" def __init__(self, editor): self.editor = editor self.dialog = TextDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 12. tools/sticker.py Python 复制 # 导入必要的模块 from PyQt5.QtWidgets import QDialog, QFileDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit from PyQt5.QtCore import Qt class StickerDialog(QDialog): """贴纸对话框类""" def __init__(self, editor): super().__init__() self.editor = editor self.setWindowTitle("添加贴纸") self.x = 50 self.y = 50 self.sticker_path = "" self.init_ui() def init_ui(self): """初始化用户界面""" # 创建 X 坐标输入框和标签 self.label_x = QLabel("X:") self.edit_x = QLineEdit("50") self.edit_x.setFixedWidth(60) # 创建 Y 坐标输入框和标签 self.label_y = QLabel("Y:") self.edit_y = QLineEdit("50") self.edit_y.setFixedWidth(60) # 创建选择贴纸按钮 self.btn_select = QPushButton("选择贴纸") self.btn_select.clicked.connect(self.select_sticker) # 创建确定和取消按钮 self.btn_ok = QPushButton("确定") self.btn_ok.clicked.connect(self.accept) self.btn_cancel = QPushButton("取消") self.btn_cancel.clicked.connect(self.reject) # 创建布局 layout = QVBoxLayout() # 添加 X 坐标输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_x) h_layout.addWidget(self.edit_x) layout.addLayout(h_layout) # 添加 Y 坐标输入 h_layout = QHBoxLayout() h_layout.addWidget(self.label_y) h_layout.addWidget(self.edit_y) layout.addLayout(h_layout) # 添加选择贴纸按钮 layout.addWidget(self.btn_select) # 添加确定和取消按钮 h_layout = QHBoxLayout() h_layout.addWidget(self.btn_ok) h_layout.addWidget(self.btn_cancel) layout.addLayout(h_layout) # 设置对话框的布局 self.setLayout(layout) def select_sticker(self): """选择贴纸文件""" file_path, _ = QFileDialog.getOpenFileName( self, "选择贴纸", "", "图像文件 (*.png *.jpg *.jpeg *.bmp)" ) if file_path: self.sticker_path = file_path def get_values(self): """获取当前的贴纸参数""" try: x = int(self.edit_x.text()) y = int(self.edit_y.text()) except ValueError: x = 50 y = 50 return x, y, self.sticker_path def accept(self): """处理确定按钮点击事件""" # 获取贴纸参数 x, y, sticker_path = self.get_values() # 添加贴纸 if self.editor.image is not None and sticker_path: # 读取贴纸图像 sticker = cv2.imread(sticker_path, cv2.IMREAD_UNCHANGED) if sticker is not None: # 获取贴纸尺寸 sticker_height, sticker_width = sticker.shape[:2] # 获取图像尺寸 img_height, img_width, _ = self.editor.image.shape # 确保贴纸在图像范围内 if x + sticker_width > img_width: x = img_width - sticker_width if y + sticker_height > img_height: y = img_height - sticker_height # 添加贴纸 for i in range(sticker_height): for j in range(sticker_width): if sticker[i, j, 3] != 0: # 检查 alpha 通道 self.editor.image[y + i, x + j] = sticker[i, j] # 将当前图像压入历史栈 self.editor.push_history() # 更新显示 self.editor.update_canvas() super().accept() class StickerTool: """贴纸工具类""" def __init__(self, editor): self.editor = editor self.dialog = StickerDialog(editor) def show_dialog(self): """显示对话框""" self.dialog.show() 13. ui/mainwindow.ui 这个文件定义了图形用户界面的布局,您可以使用 Qt Designer 创建它。以下是基本的 UI 文件内容: xml 复制 <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>图像编辑器</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QLabel" name="canvas"> <property name="text"> <string>请打开一张图片</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> </layout> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>21</height> </rect> </property> <widget class="QMenu" name="menuFile"> <property name="title"> <string>文件</string> </property> <addaction name="actionOpen"/> <addaction name="actionSave"/> </widget> <widget class="QMenu" name="menuEdit"> <property name="title"> <string>编辑</string> </property> <addaction name="actionUndo"/> <addaction name="actionRedo"/> <addaction name="actionReset"/> </widget> <widget class="QMenu" name="menuAdjust"> <property name="title"> <string>调整</string> </property> <addaction name="actionBrightnessContrast"/> <addaction name="actionBlur"/> <addaction name="actionSharpen"/> </widget> <widget class="QMenu" name="menuOperation"> <property name="title"> <string>操作</string> </property> <addaction name="actionCrop"/> <addaction name="actionRotate"/> <addaction name="actionScale"/> <addaction name="actionFlip"/> </widget> <widget class="QMenu" name="menuAdd"> <property name="title"> <string>添加</string> </property> <addaction name="actionText"/> <addaction name="actionSticker"/> </widget> <addaction name="menuFile"/> <addaction name="menuEdit"/> <addaction name="menuAdjust"/> <addaction name="menuOperation"/> <addaction name="menuAdd"/> </widget> <widget class="QStatusBar" name="statusbar"/> <action name="actionOpen"> <property name="text"> <string>打开</string> </property> </action> <action name="actionSave"> <property name="text"> <string>保存</string> </property> </action> <action name="actionUndo"> <property name="text"> <string>撤销</string> </property> </action> <action name="actionRedo"> <property name="text"> <string>重做</string> </property> </action> <action name="actionReset"> <property name="text"> <string>重置</string> </property> </action> <action name="actionBrightnessContrast"> <property name="text"> <string>亮度对比度</string> </property> </action> <action name="actionBlur"> <property name="text"> <string>模糊</string> </property> </action> <action name="actionSharpen"> <property name="text"> <string>锐化</string> </property> </action> <action name="actionCrop"> <property name="text"> <string>裁剪</string> </property> </action> <action name="actionRotate"> <property name="text"> <string>旋转</string> </property> </action> <action name="actionScale"> <property name="text"> <string>缩放</string> </property> </action> <action name="actionFlip"> <property name="text"> <string>翻转</string> </property> </action> <action name="actionText"> <property name="text"> <string>文字</string> </property> </action> <action name="actionSticker"> <property name="text"> <string>贴纸</string> </property> </action> </widget> <resources/> <connections/> </ui>代码这这,这是项目结构:ImageEditor/ ├── main.py # 主程序入口 ├── image_editor.py # 图像编辑器主类 ├── tools/ # 图像处理工具 │ ├── __init__.py # 工具包初始化 │ ├── brightness_contrast.py # 亮度对比度工具 │ ├── blur.py # 模糊工具 │ ├── sharpen.py # 锐化工具 │ ├── crop.py # 裁剪工具 │ ├── rotate.py # 旋转工具 │ ├── scale.py # 缩放工具 │ ├── flip.py # 翻转工具 │ ├── text.py # 文字工具 │ └── sticker.py # 贴纸工具 ├── ui/ # 用户界面文件 │ ├── main_window.ui # 主窗口界面 │ └── resource.qrc # 资源文件 └── resources/ # 资源文件夹 ├── stickers/ # 贴纸资源 └── fonts/ # 字体资源
最新发布
06-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值