freelsn / notes

0 stars 0 forks source link

PyQt 窗口 #3

Open freelsn opened 1 year ago

freelsn commented 1 year ago

Menu

设计菜单栏的规范

'main_window_template.py'

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        self.setMinimumSize(450, 350)
        self.setWindowTitle('Main Window Template')
        self.setUpMainWindow()
        self.createActions()
        self.createMenu()
        self.show()

    def setUpMainWindow(self):
        pass

    def createActions(self):
        self.quit_act = QAction('Quit')
        self.quit_act.setShortcut('Ctrl+Q')
        self.quit_act.triggered.connect(self.close)

    def createMenu(self):
        self.menuBar().setNativeMenuBar(False)

        file_menu = self.menuBar().addMenu('File')
        file_menu.addAction(self.quit_act)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())
freelsn commented 1 year ago

QIcon

'change_icons.py'

import sys
import random
from PyQt5.QtWidgets import (QApplication,
                             QMainWindow,
                             QWidget,
                             QLabel,
                             QPushButton,
                             QVBoxLayout)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        self.setMinimumSize(200, 200)
        self.setWindowTitle('Changing Icons Example')
        self.setWindowIcon(QIcon('images/pyqt_logo.png'))
        self.setUpMainWindow()
        self.show()

    def setUpMainWindow(self):
        info_label = QLabel('Click on the button and select a fruit')
        info_label.setAlignment(Qt.AlignCenter)

        self.images = [
            'images/1_apple.png',
            'images/2_pineapple.png',
            'images/3_watermelon.png',
            'images/4_banana.png',
        ]
        self.icon_button = QPushButton()
        self.icon_button.setIcon(QIcon(random.choice(self.images)))
        self.icon_button.setIconSize(QSize(60, 60))
        self.icon_button.clicked.connect(self.changeButtonIcon)

        main_v_box = QVBoxLayout()
        main_v_box.addWidget(info_label)
        main_v_box.addWidget(self.icon_button)

        container = QWidget()
        container.setLayout(main_v_box)
        self.setCentralWidget(container)

    def changeButtonIcon(self):
        self.icon_button.setIcon(QIcon(random.choice(self.images)))
        self.icon_button.setIconSize(QSize(60, 60))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())
freelsn commented 1 year ago

QFileDialog

The QFileDialog class can be used to open and select files or directories on your computer. This dialog class is useful for opening, saving, and naming files.

file_name, ok = QFileDialog.getOpenFileName(
    self,  # parent
    'Open File',  # caption
    '/Users/user_name/Desktop/',  # directory
    'Image Files (*.png *.jpg *.bmp)'  # filter
)

file_name, ok = QFileDialog.getSaveFileName(
    self,  # parent
    'Open File',  # caption
    '/Users/user_name/Desktop/',  # directory
    'Image Files (*.png *.jpg *.bmp)',  # filter
    options=QFileDialog.DontUseNativeDialog
)

QInputDialog

QInputDialog is a native dialog in PyQt that can be used to receive input from the user. The input is a single value that can be a string, a number, or an item from a list.

file_name, ok = QInputDialog.getText(
    self,  # parent
    'Search Text',  # title
    'Find:',  # label
)

Other types of input can be collected using one of the following QInputDialog methods:

QFontDialog

QFontDialog provides a dialog box that allows the user to select and manipulate different types of fonts.

font, ok = QFontDialog.getFont()

font, ok = QFontDialog.getFont(QFont('Helvetica', 10), self)  # provide default font

QColorDialog

The QColorDialog class creates a dialog box for selecting colors.

QMessageBox.about

QMessageBox.about(
    self,  # parent
    'About Notepad',  # caption
    """<p>Beginner's Practical Guide to PyQt</p>
    <p>Project 5.1 - Notepad GUI</p>"""  # text
)
freelsn commented 1 year ago
'richtext_notepad.py'

import sys
from PyQt5.QtWidgets import (QApplication,
                             QMainWindow,
                             QMessageBox,
                             QTextEdit,
                             QFileDialog,
                             QInputDialog,
                             QFontDialog,
                             QColorDialog,
                             QAction)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon, QTextCursor, QColor

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        self.setMinimumSize(400, 500)
        self.setWindowTitle('Rich Text Notepad GUI')
        self.setUpMainWindow()
        self.createActions()
        self.createMenu()
        self.show()

    def setUpMainWindow(self):
        self.text_edit = QTextEdit()
        self.text_edit.textChanged.connect(self.removeHighlights)
        self.setCentralWidget(self.text_edit)

    def createActions(self):

        def create(name, icon, slot, shortcut=None):
            act = QAction(QIcon(icon), name)
            if shortcut:
                act.setShortcut(shortcut)
            act.triggered.connect(slot)
            return act

        self.new_act = create('New', 'images/new_file.png',
                              self.clearText, 'Ctrl+N')
        self.open_act = create('Open', 'images/open_file.png',
                               self.openFile, 'Ctrl+O')
        self.save_act = create('Save', 'images/save_file.png',
                               self.saveToFile, 'Ctrl+S')
        self.quit_act = create('Quit', 'images/exit.png',
                               self.close, 'Ctrl+Q')

        self.undo_act = create('Undo', 'images/undo.png',
                               self.text_edit.undo, 'Ctrl+Z')
        self.redo_act = create('Redo', 'images/redo.png',
                               self.text_edit.redo, 'Ctrl+Shift+Z')
        self.cut_act = create('Cut', 'images/cut.png',
                               self.text_edit.cut, 'Ctrl+X')
        self.copy_act = create('Copy', 'images/copy.png',
                               self.text_edit.copy, 'Ctrl+C')
        self.paste_act = create('Paste', 'images/paste.png',
                               self.text_edit.paste, 'Ctrl+V')
        self.find_act = create('Find All', 'images/find.png',
                               self.searchText, 'Ctrl+F')

        self.font_act = create('Font', 'images/font.png',
                               self.chooseFont, 'Ctrl+T')
        self.color_act = create('Color', 'images/color.png',
                               self.chooseFontColor, 'Ctrl+Shift+C')
        self.highlight_act = create('Highlight', 'images/highlight.png',
                               self.chooseFontBackgroundColor, 'Ctrl+Shift+H')

        self.about_act = create('About', 'images/print.png',
                               self.aboutDialog)

    def createMenu(self):
        self.menuBar().setNativeMenuBar(False)

        file_menu = self.menuBar().addMenu('File')
        file_menu.addAction(self.new_act)
        file_menu.addSeparator()
        file_menu.addAction(self.open_act)
        file_menu.addAction(self.save_act)
        file_menu.addSeparator()
        file_menu.addAction(self.quit_act)

        edit_menu = self.menuBar().addMenu('Edit')
        edit_menu.addAction(self.undo_act)
        edit_menu.addAction(self.redo_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.cut_act)
        edit_menu.addAction(self.copy_act)
        edit_menu.addAction(self.paste_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.find_act)

        tool_menu = self.menuBar().addMenu('Tools')
        tool_menu.addAction(self.font_act)
        tool_menu.addAction(self.color_act)
        tool_menu.addAction(self.highlight_act)

        help_menu = self.menuBar().addMenu('Help')
        help_menu.addAction(self.about_act)

    def clearText(self):
        answer = QMessageBox.question(
            self,
            'Clear Text',
            'Do you want to clear the text?',
            QMessageBox.No | QMessageBox.Yes,
            QMessageBox.Yes
        )
        if answer == QMessageBox.Yes:
            self.text_edit.clear()

    def openFile(self):
        file_name, _ = QFileDialog.getOpenFileName(
            self,
            'Open File',
            '',
            'HTML Files (*.html);;Text Files (*.txt)'
        )
        if file_name:
            self.text_edit.setText(open(file_name).read())

    def saveToFile(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self,
            'Save File',
            '',
            'HTML Files (*.html);;Text Files (*.txt)'
        )
        if file_name.endswith('.txt'):
            open(file_name, 'w').write(self.text_edit.toPlainText())
        elif file_name.endswith('.html'):
            open(file_name, 'w').write(self.text_edit.toHtml())
        else:
            QMessageBox.information(
                self,
                'Not Saved',
                'Text not saved.',
                QMessageBox.Ok
            )

    def searchText(self):
        find_text, ok = QInputDialog.getText(
            self,
            'Search Text',
            'Find:'
        )
        if ok:
            extra_selections = []
            self.text_edit.moveCursor(QTextCursor.Start)
            color = QColor(Qt.gray)
            while self.text_edit.find(find_text):
                selection = QTextEdit.ExtraSelection()
                selection.format.setBackground(color)
                selection.cursor = self.text_edit.textCursor()
                extra_selections.append(selection)
            self.text_edit.setExtraSelections(extra_selections)

    def removeHighlights(self):
        self.text_edit.setExtraSelections([])

    def chooseFont(self):
        font, ok = QFontDialog.getFont(
            self.text_edit.currentFont(),
            self,
            options=QFontDialog.DontUseNativeDialog
        )
        if ok:
            self.text_edit.setCurrentFont(font)

    def chooseFontColor(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.text_edit.setTextColor(color)

    def chooseFontBackgroundColor(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.text_edit.setTextBackgroundColor(color)

    def aboutDialog(self):
        QMessageBox.about(
            self,
            'About Notepad',
            """<p>Beginner's Practical Guide to PyQt</p>
            <p>Project 5.1 - Notepad GUI</p>"""
        )

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())
freelsn commented 1 year ago

QStatusBar

This widget is very useful for displaying feedback, extra information about a widget, or the outcome of a process.

QToolBar

When the user is performing a number of routine tasks, having to open up the menu to select an action multiple times can become tedious. Luckily, the QToolBar class provides ways to create a toolbar with icons, text, or standard Qt widgets for quick access to frequently used commands.

A GUI can only have one menu bar, but it can have multiple toolbars.

QDockWidget

The QDockWidget class is used to create detachable or floating tool palettes or widget panels. Dock widgets are secondary windows that provide additional functionality to GUI windows.

'main_window_extras.py'

import sys
from PyQt5.QtWidgets import (QApplication,
                             QMainWindow,
                             QWidget,
                             QCheckBox,
                             QTextEdit,
                             QDockWidget,
                             QToolBar,
                             QStatusBar,
                             QVBoxLayout,
                             QAction)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        self.setMinimumSize(450, 350)
        self.setWindowTitle('Adding More Window Features')
        self.setUpMainWindow()
        self.createDockWidget()
        self.createActions()
        self.createMenu()
        self.createToolBar()
        self.show()

    def setUpMainWindow(self):
        self.text_edit = QTextEdit()
        self.setCentralWidget(self.text_edit)
        self.setStatusBar(QStatusBar())

    def createActions(self):
        self.quit_act = QAction(QIcon('images/exit.png'), 'Quit')
        self.quit_act.setShortcut('Ctrl+Q')
        self.quit_act.setStatusTip('Quit program')
        self.quit_act.triggered.connect(self.close)

        self.full_screen_act = QAction('Full Screen', checkable=True)
        self.full_screen_act.setStatusTip('Switch to full screen mode')
        self.full_screen_act.triggered.connect(self.switchToFullScreen)

    def createMenu(self):
        self.menuBar().setNativeMenuBar(False)

        file_menu = self.menuBar().addMenu('File')
        file_menu.addAction(self.quit_act)

        view_menu = self.menuBar().addMenu('View')
        appearance_submenu = view_menu.addMenu('Appearance')
        appearance_submenu.addAction(self.full_screen_act)

    def switchToFullScreen(self, state):
        if state:
            self.showFullScreen()
        else:
            self.showNormal()

    def createToolBar(self):
        toolbar = QToolBar('Main Toolbar')
        toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(toolbar)
        toolbar.addAction(self.quit_act)

    def createDockWidget(self):
        dock_widget = QDockWidget()
        dock_widget.setWindowTitle('Formatting')
        dock_widget.setAllowedAreas(Qt.AllDockWidgetAreas)

        auto_bullet_cb = QCheckBox('Auto Bullet List')
        auto_bullet_cb.toggled.connect(self.changeTextEditSettings)

        dock_v_box = QVBoxLayout()
        dock_v_box.addWidget(auto_bullet_cb)
        dock_v_box.addStretch(1)

        dock_container = QWidget()
        dock_container.setLayout(dock_v_box)

        dock_widget.setWidget(dock_container)

        self.addDockWidget(Qt.LeftDockWidgetArea, dock_widget)

    def changeTextEditSettings(self, checked):
        if checked:
            self.text_edit.setAutoFormatting(QTextEdit.AutoBulletList)
        else:
            self.text_edit.setAutoFormatting(QTextEdit.AutoNone)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())
freelsn commented 1 year ago
'photo_editor.py'

import sys
from PyQt5.QtWidgets import (QApplication,
                             QMainWindow,
                             QWidget,
                             QLabel,
                             QPushButton,
                             QDockWidget,
                             QDialog,
                             QFileDialog,
                             QMessageBox,
                             QToolBar,
                             QStatusBar,
                             QVBoxLayout,
                             QAction)
from PyQt5.QtCore import Qt, QSize, QRect
from PyQt5.QtGui import QIcon, QPixmap, QTransform, QPainter
from PyQt5.QtPrintSupport import QPrinter, QPrintDialog

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        self.setFixedSize(650, 650)
        self.setWindowTitle('Photo Editor GUI')
        self.setUpMainWindow()
        self.createToolsDockwidget()
        self.createActions()
        self.createMenu()
        self.createToolBar()
        self.show()

    def setUpMainWindow(self):
        self.image = QPixmap()
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignCenter)
        self.setCentralWidget(self.image_label)
        self.setStatusBar(QStatusBar())

    def createActions(self):

        def create(name, slot, tip, icon=None, shortcut=None):
            if icon:
                act = QAction(QIcon(icon), name)
            else:
                act = QAction(name)
            if shortcut:
                act.setShortcut(shortcut)
            act.setStatusTip(tip)
            act.triggered.connect(slot)
            return act

        self.open_act = create('Open', self.openImage, 'Open a new image',
                               'images/open_file.png', 'Ctrl+O')
        self.save_act = create('Save', self.saveImage, 'Save image',
                               'images/save_file.png', 'Ctrl+S')
        self.print_act = create('Print', self.printImage, 'Print image',
                                'images/print.png', 'Ctrl+P')
        self.print_act.setEnabled(False)
        self.quit_act = create('Quit', self.close, 'Quit program',
                               'images/exit.png', 'Ctrl+Q')

        self.rotate90_act = create('Rotate 90', self.rotateImage90,
                                   'Rotate image 90 degree clockwise')
        self.rotate180_act = create('Rotate 180', self.rotateImage180,
                                    'Rotate image 180 degree clockwise')
        self.flip_hor_act = create('Flip Horizontal', self.flipImageHorizontal,
                                   'Flip image across horizontal axis')
        self.flip_ver_act = create('Flip Vertical', self.flipImageVertical,
                                   'Flip image across vertical axis')
        self.resize_act = create('Resize Half', self.resizeImageHalf,
                                 'Resize image to half the original size')
        self.clear_act = create('Clear Image', self.clearImage,
                                'Clear the current image', 'images/clear.png',
                                'Ctrl+D')

    def createMenu(self):
        self.menuBar().setNativeMenuBar(False)

        file_menu = self.menuBar().addMenu('File')
        file_menu.addAction(self.open_act)
        file_menu.addAction(self.save_act)
        file_menu.addSeparator()
        file_menu.addAction(self.print_act)
        file_menu.addSeparator()
        file_menu.addAction(self.quit_act)

        edit_menu = self.menuBar().addMenu('Edit')
        edit_menu.addAction(self.rotate90_act)
        edit_menu.addAction(self.rotate180_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.flip_hor_act)
        edit_menu.addAction(self.flip_ver_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.resize_act)
        edit_menu.addSeparator()
        edit_menu.addAction(self.clear_act)

        view_menu = self.menuBar().addMenu('View')
        view_menu.addAction(self.toggle_dock_tools_act)

    def createToolBar(self):
        tool_bar = QToolBar('Photo Editor Toolbar')
        tool_bar.setIconSize(QSize(24, 24))
        self.addToolBar(tool_bar)

        tool_bar.addAction(self.open_act)
        tool_bar.addAction(self.save_act)
        tool_bar.addAction(self.print_act)
        tool_bar.addAction(self.clear_act)
        tool_bar.addSeparator()
        tool_bar.addAction(self.quit_act)

    def createToolsDockwidget(self):
        dock_widget = QDockWidget()
        dock_widget.setWindowTitle('Edit Image Tools')
        dock_widget.setAllowedAreas(
            Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

        def create(name, tip, slot):
            btn = QPushButton(name)
            btn.setMinimumSize(QSize(130, 40))
            btn.setStatusTip(tip)
            btn.clicked.connect(slot)
            return btn

        self.rotate90 = create('Rotate 90', 'Rotate image 90 clockwise',
                               self.rotateImage90)
        self.rotate180 = create('Rotate 180', 'Rotate image 180 clockwise',
                               self.rotateImage180)
        self.flip_horizontal = create('Flip Horizontal',
                                      'Flip image across horizontal axis',
                                      self.flipImageHorizontal)
        self.flip_vertical = create('Flip vertical',
                                    'Flip image across vertical axis',
                                    self.flipImageVertical)
        self.resize_half = create('Resize Half',
                                  'Resize image to half the original size',
                                  self.resizeImageHalf)

        dock_v_box = QVBoxLayout()
        dock_v_box.addWidget(self.rotate90)
        dock_v_box.addWidget(self.rotate180)
        dock_v_box.addStretch(1)
        dock_v_box.addWidget(self.flip_horizontal)
        dock_v_box.addWidget(self.flip_vertical)
        dock_v_box.addStretch(1)
        dock_v_box.addWidget(self.resize_half)
        dock_v_box.addStretch(1)

        tools_container = QWidget()
        tools_container.setLayout(dock_v_box)
        dock_widget.setWidget(tools_container)

        self.addDockWidget(Qt.RightDockWidgetArea, dock_widget)

        self.toggle_dock_tools_act = dock_widget.toggleViewAction()

    def _scale_image_in_label(self):
        self.image_label.setPixmap(
            self.image.scaled(self.image_label.size(),
                              Qt.KeepAspectRatio,
                              Qt.SmoothTransformation)
        )

    def openImage(self):
        image_file, _ = QFileDialog.getOpenFileName(
            self,
            'Open Image',
            '',
            'JPG Files (*.jpeg *.jpg);;\
             PNG Files (*.png);;\
             Bitmap Files (*.bmp);;\
             GIF Files (*.gif)'
        )
        if image_file:
            self.image = QPixmap(image_file)
            self._scale_image_in_label()
            self.print_act.setEnabled(True)
        else:
            QMessageBox.information(
                self,
                'No Image',
                'No Image Selected',
                QMessageBox.Ok
            )

    def saveImage(self):
        image_file, _ = QFileDialog.getSaveFileName(
            self,
            'Save Image',
            '',
            ''
            'JPG Files (*.jpeg *.jpg);;\
             PNG Files (*.png);;\
             Bitmap Files (*.bmp);;\
             GIF Files (*.gif)'
        )
        if image_file and not self.image.isNull():
            self.image.save(image_file)
        else:
            QMessageBox.information(
                self,
                'Not Saved',
                'Image not saved.',
                QMessageBox.Ok
            )

    def clearImage(self):
        self.image_label.clear()
        self.image = QPixmap()
        self.print_act.setEnabled(False)

    def _edit_image(self, transform):
        pixmap = QPixmap(self.image)
        new = pixmap.transformed(transform, Qt.SmoothTransformation)
        self._scale_image_in_label()
        self.image = QPixmap(new)
        self.image_label.repaint()

    def rotateImage90(self):
        if not self.image.isNull():
            self._edit_image(QTransform().rotate(90))

    def rotateImage180(self):
        if not self.image.isNull():
            self._edit_image(QTransform().rotate(180))

    def flipImageHorizontal(self):
        if not self.image.isNull():
            self._edit_image(QTransform().scale(-1, 1))

    def flipImageVertical(self):
        if not self.image.isNull():
            self._edit_image(QTransform().scale(1, -1))

    def resizeImageHalf(self):
        if not self.image.isNull():
            self._edit_image(QTransform().scale(0.5, 0.5))

    def printImage(self):
        printer = QPrinter()
        print_dialog = QPrintDialog(printer)
        if print_dialog.exec() == QDialog.Accepted:
            painter = QPainter()
            painter.begin(printer)
            rect = QRect(painter.viewport())
            size = QSize(self.image_label.pixmap().size())
            size.scale(rect.size(), Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
            painter.setWindow(self.image_label.pixmap().rect())
            painter.drawPixmap(0, 0, self.image_label.pixmap())
            painter.end()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setAttribute(Qt.AA_DontShowIconsInMenus, True)
    window = MainWindow()
    sys.exit(app.exec())