LoginSignup
83
83

More than 5 years have passed since last update.

PyQt5とpython3によるGUIプログラミング[1]

Last updated at Posted at 2016-06-12

シンプルなウィンドウ

window01.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import  *


def main():
    app = QApplication(sys.argv)
    w = QWidget()
    w.resize(250, 150)
    w.setWindowTitle('Window01')
    w.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

window01.png

これが全ての始まりです。

ウィンドウのリサイズを許さない

DonotResize.py
import sys
import time
from PyQt5.QtWidgets import *

class SampleWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setWindowTitle("Sample Window")
        self.setGeometry(300, 300, 200, 150)
        self.setMinimumHeight(100)
        self.setMinimumWidth(250)
        self.setMaximumHeight(100)
        self.setMaximumWidth(250)

if __name__ == '__main__':

        myApp = QApplication(sys.argv)
        myWindow = SampleWindow()
        myWindow.show()
        myApp.exec_()
        sys.exit(0)

MinimumとMaximumに同じ値を設定することで、リサイズを抑止します。

スクリーンショット 2016-10-29 13.50.50.png

ボタンでイベント発生

Button01.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-

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


class Button01(QMainWindow):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        btn1 = QPushButton("Button01", self)
        btn1.clicked.connect(self.button01Clicked)

        self.statusBar()

        self.setWindowTitle('Button01')
        self.show()

    def button01Clicked(self):
        sender = self.sender()
        self.statusBar().showMessage(sender.text() + ' Push Button01')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Button01()
    sys.exit(app.exec_())

image

senderメソッドはQWidgetクラスに入っているのでほとんどのウィジットで利用できます。
senderメソッドを使用することで、直前にシグナルを送ってきたウィジットを返してくれます。
帰ってくるのは、ウィジットのインスタンスになります。
何個でも設定できるようです。
複数のボタンがある場合など、どのボタンが押されたのか判定するときなど有効です。

Color Dialogで色を変える

ColorDialog.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.Qt import *

class ColorDialog(QWidget):

    def __init__(self):
        super(ColorDialog, self).__init__(parent=None)
        thisColor = QColor(0, 0, 0)

        self.ColorButton = QPushButton('Select Color', self)
        self.ColorButton.move(27, 15)

        #Qpainterを使う方法もあるが、ここではbackground-colorを設定することで色を変えてみる
        self.myFrame = QFrame(self)
        self.myFrame.setStyleSheet("QWidget { background-color: %s }" % thisColor.name())
        self.myFrame.setGeometry(75, 50, 25, 25)

        self.ColorButton.clicked.connect(self.showDialog)

        self.setGeometry(200, 100, 175, 100)
        self.setWindowTitle('Color Dialog')

        self.show()

    def showDialog(self):
        #ダイアログを表示する
        getcolor = QColorDialog.getColor()

        if getcolor.isValid():
            self.myFrame.setStyleSheet("QWidget { background-color: %s }" % getcolor.name())

if __name__ =='__main__':
        App = QApplication(sys.argv)
        dialog = ColorDialog()
        dialog.show()
        App.exec_()
        sys.exit()

スクリーンショット 2016-10-05 23.15.32.png

Signals and Slots

PyQt4とPyQt5ではSignalとSlotのコーディングスタイルが全くというほど異なります。
以下のページはpysideのコンテンツですが、脳内変換すればPyQt5でも全く問題なく利用できます。
https://wiki.qt.io/Signals_and_Slots_in_PySide/ja

自分で作成したSignal、Slotを利用する場合、大変役に立つはずです。

カスタムシグナルサンプル

MySignal.py
import sys
from PyQt5.QtCore import *

class CustomSignal(QObject):

    mySignal = pyqtSignal(str)

def printstr(text):
    print(text)

if __name__ == '__main__':

    myObject = CustomSignal()

    myObject.mySignal.connect(printstr)

    myObject.mySignal.emit("カスタムシグナル!")

実行例.png

PyScripterでの実行例です。

イベントサンプル

EventTest01.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class EventTest01(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        WiNum = QLCDNumber(self)
        Stool = QSlider(Qt.Horizontal, self)
        BoxLay = QVBoxLayout()
        BoxLay.addWidget(WiNum)
        BoxLay.addWidget(Stool)
        self.setLayout(BoxLay)
        Stool.valueChanged.connect(WiNum.display)
        self.setGeometry(500, 500, 300, 200)
        self.setWindowTitle('EventTest')
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = EventTest01()
    sys.exit(app.exec_())

image

イベントサンプルその2

フレームの上でマウスボタンをクリックするとコンソールにボタンの位置をプリントします。

EventTest02.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.Qt import *

class Test(QWidget):
    def __init__(self,parent=None):
        super(Test, self).__init__(parent)
        self.label = QLabel(self)
        self.label.setText('テストボックス')

        #http://doc.qt.io/qt-5/qt.html
        #上記のページに他の設定もあります
        self.label.setAlignment(Qt.AlignCenter)

        #http://doc.qt.io/qt-5/qframe.html
        #上記のページに他の設定もあります
        self.label.setFrameStyle(QFrame.Panel | QFrame.Raised)
        self.label.setLineWidth(2)

        #マウストラッキングが有効になっている場合、ウィジェットはボタンを押さない場合でも、マウス移動イベントを受け取ります。
        self.label.setMouseTracking(True)

        self.label.installEventFilter(self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.label)

    def eventFilter(self, object, event):
        if event.type() == QEvent.MouseButtonPress and object is self.label:
            pos = event.pos()
            print('MouseButtonPress: (%d, %d)' % (pos.x(), pos.y()))
        return QWidget.eventFilter(self, object, event)

if __name__ == '__main__':

    import sys
    app = QApplication(sys.argv)
    window = Test()
    window.show()
    window.resize(300, 150)
    sys.exit(app.exec_())

スクリーンショット 2016-11-04 14.17.07.png

PyQt4とPyQt5のコーディングスタイルの違い

PyQt4とpython2.Xで動いていたものが、PyQt5とpython3.Xでは動かないことが
よくあります。

これなどもその例で、

PyQt4:python2.X
settings.value("/myboolsetting", True).toBool()
settings.value("/myintsetting", 10).toInt()[0]
settings.value("/myintsetting").toByteArray()
PyQt5:python3.X
settings.value("/myboolsetting", True, type=bool)
settings.value("/myintsetting", 10, type=int)
settings.value("/myintsetting", QByteArray(), type=QByteArray)

上記のようにコーディングする必要があるそうだ。
これは、"toXXXX"系のメソッドが削除されていることが原因のようだ。

QStringのメソッドは軒並み使えない、そもそもPyQt5にはQStringは存在しない。

PyQt4:python2.X
if mystr.isEmpty()
mystr = QStringList()
myval = QVariant(5)
myval = QVariant("Good Morning")
PyQt5:python3.X
if not mystr
mystr = []
myval = 5
myval = "Good Morning"

他にもあるようだけれども、今後見つけたら追加したい。

QByteArrayを返すQt5のクラスを使用するとPython3で動かない場合がある

PyQt5のexamplesにscribble.pyがあります、これは2.xでは動くのですが、3.xでは保存時のformat部分でエラーが出てしまう。

この場合、以下の部分を

    def createActions(self):
        self.openAct = QAction("&Open...", self, shortcut="Ctrl+O",
                triggered=self.open)

        for format in QImageWriter.supportedImageFormats():
            format = str(format)

            text = format.upper() + "..."

こうすることで動きます。

    def createActions(self):
        self.openAct = QAction("&Open...", self, shortcut="Ctrl+O",
                triggered=self.open)

        for format in QImageWriter.supportedImageFormats():
            aaaaa = bytes(format)
            #format = str(format)
            format = aaaaa.decode('utf-8')

            text = format.upper() + "..."

2.xの時はstrでキャストするだけで動いたようですが、3.xではdecodeしてあげないと上手くいきません。

一応コードは掲載しておきます。
ただ、これはあくまでもPyQt5のexamplesのコードです。

Scribble.py
from PyQt5.QtCore import QDir, QPoint, QRect, QSize, Qt
from PyQt5.QtGui import QImage, QImageWriter, QPainter, QPen, qRgb
from PyQt5.QtWidgets import (QAction, QApplication, QColorDialog, QFileDialog,
        QInputDialog, QMainWindow, QMenu, QMessageBox, QWidget)
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter


class ScribbleArea(QWidget):
    def __init__(self, parent=None):
        super(ScribbleArea, self).__init__(parent)

        self.setAttribute(Qt.WA_StaticContents)
        self.modified = False
        self.scribbling = False
        self.myPenWidth = 1
        self.myPenColor = Qt.blue
        self.image = QImage()
        self.lastPoint = QPoint()

    def openImage(self, fileName):
        loadedImage = QImage()
        if not loadedImage.load(fileName):
            return False

        newSize = loadedImage.size().expandedTo(self.size())
        self.resizeImage(loadedImage, newSize)
        self.image = loadedImage
        self.modified = False
        self.update()
        return True

    def saveImage(self, fileName, fileFormat):
        visibleImage = self.image
        self.resizeImage(visibleImage, self.size())

        if visibleImage.save(fileName, fileFormat):
            self.modified = False
            return True
        else:
            return False

    def setPenColor(self, newColor):
        self.myPenColor = newColor

    def setPenWidth(self, newWidth):
        self.myPenWidth = newWidth

    def clearImage(self):
        self.image.fill(qRgb(255, 255, 255))
        self.modified = True
        self.update()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.lastPoint = event.pos()
            self.scribbling = True

    def mouseMoveEvent(self, event):
        if (event.buttons() & Qt.LeftButton) and self.scribbling:
            self.drawLineTo(event.pos())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton and self.scribbling:
            self.drawLineTo(event.pos())
            self.scribbling = False

    def paintEvent(self, event):
        painter = QPainter(self)
        dirtyRect = event.rect()
        painter.drawImage(dirtyRect, self.image, dirtyRect)

    def resizeEvent(self, event):
        if self.width() > self.image.width() or self.height() > self.image.height():
            newWidth = max(self.width() + 128, self.image.width())
            newHeight = max(self.height() + 128, self.image.height())
            self.resizeImage(self.image, QSize(newWidth, newHeight))
            self.update()

        super(ScribbleArea, self).resizeEvent(event)

    def drawLineTo(self, endPoint):
        painter = QPainter(self.image)
        painter.setPen(QPen(self.myPenColor, self.myPenWidth, Qt.SolidLine,
                Qt.RoundCap, Qt.RoundJoin))
        painter.drawLine(self.lastPoint, endPoint)
        self.modified = True

        rad = self.myPenWidth / 2 + 2
        self.update(QRect(self.lastPoint, endPoint).normalized().adjusted(-rad, -rad, +rad, +rad))
        self.lastPoint = QPoint(endPoint)

    def resizeImage(self, image, newSize):
        if image.size() == newSize:
            return

        newImage = QImage(newSize, QImage.Format_RGB32)
        newImage.fill(qRgb(255, 255, 255))
        painter = QPainter(newImage)
        painter.drawImage(QPoint(0, 0), image)
        self.image = newImage

    def print_(self):
        printer = QPrinter(QPrinter.HighResolution)

        printDialog = QPrintDialog(printer, self)
        if printDialog.exec_() == QPrintDialog.Accepted:
            painter = QPainter(printer)
            rect = painter.viewport()
            size = self.image.size()
            size.scale(rect.size(), Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
            painter.setWindow(self.image.rect())
            painter.drawImage(0, 0, self.image)
            painter.end()

    def isModified(self):
        return self.modified

    def penColor(self):
        return self.myPenColor

    def penWidth(self):
        return self.myPenWidth


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

        self.saveAsActs = []

        self.scribbleArea = ScribbleArea()
        self.setCentralWidget(self.scribbleArea)

        self.createActions()
        self.createMenus()

        self.setWindowTitle("Scribble")
        self.resize(500, 500)

    def closeEvent(self, event):
        if self.maybeSave():
            event.accept()
        else:
            event.ignore()

    def open(self):
        if self.maybeSave():
            fileName, _ = QFileDialog.getOpenFileName(self, "Open File",
                    QDir.currentPath())
            if fileName:
                self.scribbleArea.openImage(fileName)

    def save(self):
        action = self.sender()
        fileFormat = action.data()
        self.saveFile(fileFormat)

    def penColor(self):
        newColor = QColorDialog.getColor(self.scribbleArea.penColor())
        if newColor.isValid():
            self.scribbleArea.setPenColor(newColor)

    def penWidth(self):
        newWidth, ok = QInputDialog.getInt(self, "Scribble",
                "Select pen width:", self.scribbleArea.penWidth(), 1, 50, 1)
        if ok:
            self.scribbleArea.setPenWidth(newWidth)

    def about(self):
        QMessageBox.about(self, "About Scribble",
                "<p>The <b>Scribble</b> example shows how to use "
                "QMainWindow as the base widget for an application, and how "
                "to reimplement some of QWidget's event handlers to receive "
                "the events generated for the application's widgets:</p>"
                "<p> We reimplement the mouse event handlers to facilitate "
                "drawing, the paint event handler to update the application "
                "and the resize event handler to optimize the application's "
                "appearance. In addition we reimplement the close event "
                "handler to intercept the close events before terminating "
                "the application.</p>"
                "<p> The example also demonstrates how to use QPainter to "
                "draw an image in real time, as well as to repaint "
                "widgets.</p>")

    def createActions(self):
        self.openAct = QAction("&Open...", self, shortcut="Ctrl+O",
                triggered=self.open)

        for format in QImageWriter.supportedImageFormats():
            aaaaa = bytes(format)
            #format = str(format)
            format = aaaaa.decode('utf-8')
            print("format: %s" % format)

            text = format.upper() + "..."

            action = QAction(text, self, triggered=self.save)
            action.setData(format)
            self.saveAsActs.append(action)

        self.printAct = QAction("&Print...", self,
                triggered=self.scribbleArea.print_)

        self.exitAct = QAction("E&xit", self, shortcut="Ctrl+Q",
                triggered=self.close)

        self.penColorAct = QAction("&Pen Color...", self,
                triggered=self.penColor)

        self.penWidthAct = QAction("Pen &Width...", self,
                triggered=self.penWidth)

        self.clearScreenAct = QAction("&Clear Screen", self, shortcut="Ctrl+L",
                triggered=self.scribbleArea.clearImage)

        self.aboutAct = QAction("&About", self, triggered=self.about)

        self.aboutQtAct = QAction("About &Qt", self,
                triggered=QApplication.instance().aboutQt)

    def createMenus(self):
        self.saveAsMenu = QMenu("&Save As", self)
        for action in self.saveAsActs:
            self.saveAsMenu.addAction(action)

        fileMenu = QMenu("&File", self)
        fileMenu.addAction(self.openAct)
        fileMenu.addMenu(self.saveAsMenu)
        fileMenu.addAction(self.printAct)
        fileMenu.addSeparator()
        fileMenu.addAction(self.exitAct)

        optionMenu = QMenu("&Options", self)
        optionMenu.addAction(self.penColorAct)
        optionMenu.addAction(self.penWidthAct)
        optionMenu.addSeparator()
        optionMenu.addAction(self.clearScreenAct)

        helpMenu = QMenu("&Help", self)
        helpMenu.addAction(self.aboutAct)
        helpMenu.addAction(self.aboutQtAct)

        self.menuBar().addMenu(fileMenu)
        self.menuBar().addMenu(optionMenu)
        self.menuBar().addMenu(helpMenu)

    def maybeSave(self):
        if self.scribbleArea.isModified():
            ret = QMessageBox.warning(self, "Scribble",
                        "The image has been modified.\n"
                        "Do you want to save your changes?",
                        QMessageBox.Save | QMessageBox.Discard |
                        QMessageBox.Cancel)
            if ret == QMessageBox.Save:
                return self.saveFile('png')
            elif ret == QMessageBox.Cancel:
                return False

        return True

    def saveFile(self, fileFormat):

        print("fileFormat:%s" % fileFormat)
        initialPath = QDir.currentPath() + '/untitled.' + fileFormat

        fileName, _ = QFileDialog.getSaveFileName(self, "Save As", initialPath,
                "%s Files (*.%s);;All Files (*)" % (fileFormat.upper(), fileFormat))

        if fileName:
            return self.scribbleArea.saveImage(fileName, fileFormat)

        return False


if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

スクリーンショット 2016-08-15 22.58.57.png

まあこんな感じです。
これちょと、いじってみようと思っています。

Macでアプリケーションのアイコンを表示したい

しばらく見ていなかったら、Macでアプリケーションのアイコンが表示されていません。というか、アイコンが出てこない。
うーん、OSのアップグレードが原因かとか調べていると、こんなページを発見
https://stackoverflow.com/questions/35864177/why-using-pyqt5-on-mac-can-not-add-a-icon

以下のiconを表示してみようと思います。
icon0.png

icontest.py
import sys
import os
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon

class Example(QWidget):
    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300,300,300,220)
        self.setWindowTitle('Icon')
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'icon_2.png')
    app.setWindowIcon(QIcon(path))
    ex = Example()
    sys.exit(app.exec_())

スクリーンショット 2018-05-03 15.56.32.png

QGraphicsSceneとQGraphicsItemを少々いじってみた

ずっとこの動画が気になっていたんですが、なかなかうまく行かず、何度もも挑戦してました。
QGraphics Basic Example
似たようなことができるようになったんで、YouTubeに動画アップしてみようと思います。
画像的にはこんな感じ、codeは雑です、利用しやすいようにclassでガチガチにはしていません。
これが、正しい使い方なのかも正直わかりません、間違いがあったらどんどんご指摘ください。

PyQt5_mov
スクリーンショット 2018-07-03 15.48.06.png

ソースは下記に入れますが、以下に承諾された方のみご使用ください。
1.ソースのご利用は利用者の責任において行ってください。個人・法人に限らず利用者は自由に使用することができます。
2.ソースの利用、またはリンク先により生じた損害に対する責任を作者(ケンあずま)は負いません。
3.ソフトを利用した事によるいかなる損害も作者(ケンあずま)は一切の責任を負いません。
4.ソフトは自己の責任の上で使用して下さい。

ui_test_Dialog01.py
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'test_Dialog01.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog_graphic(object):
    def setupUi(self, Dialog_graphic):
        Dialog_graphic.setObjectName("Dialog_graphic")
        Dialog_graphic.resize(1187, 988)
        self.graphicsView = QtWidgets.QGraphicsView(Dialog_graphic)
        self.graphicsView.setGeometry(QtCore.QRect(0, 0, 991, 971))
        self.graphicsView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.graphicsView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.graphicsView.setObjectName("graphicsView")
        self.pushButton_rect = QtWidgets.QPushButton(Dialog_graphic)
        self.pushButton_rect.setGeometry(QtCore.QRect(1020, 30, 113, 32))
        self.pushButton_rect.setObjectName("pushButton_rect")
        self.pushButton_rotate = QtWidgets.QPushButton(Dialog_graphic)
        self.pushButton_rotate.setGeometry(QtCore.QRect(1020, 210, 113, 32))
        self.pushButton_rotate.setObjectName("pushButton_rotate")
        self.pushButton_linecolor = QtWidgets.QPushButton(Dialog_graphic)
        self.pushButton_linecolor.setGeometry(QtCore.QRect(1020, 500, 112, 34))
        self.pushButton_linecolor.setObjectName("pushButton_linecolor")
        self.pushButton_fillcolor = QtWidgets.QPushButton(Dialog_graphic)
        self.pushButton_fillcolor.setGeometry(QtCore.QRect(1020, 570, 112, 34))
        self.pushButton_fillcolor.setObjectName("pushButton_fillcolor")
        self.frame_linecolor = QtWidgets.QFrame(Dialog_graphic)
        self.frame_linecolor.setGeometry(QtCore.QRect(1060, 530, 41, 21))
        self.frame_linecolor.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_linecolor.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_linecolor.setObjectName("frame_linecolor")
        self.frame_fillcolor = QtWidgets.QFrame(Dialog_graphic)
        self.frame_fillcolor.setGeometry(QtCore.QRect(1060, 600, 41, 21))
        self.frame_fillcolor.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_fillcolor.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_fillcolor.setObjectName("frame_fillcolor")
        self.layoutWidget = QtWidgets.QWidget(Dialog_graphic)
        self.layoutWidget.setGeometry(QtCore.QRect(1030, 420, 111, 28))
        self.layoutWidget.setObjectName("layoutWidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label_line = QtWidgets.QLabel(self.layoutWidget)
        font = QtGui.QFont()
        font.setPointSize(13)
        self.label_line.setFont(font)
        self.label_line.setObjectName("label_line")
        self.horizontalLayout.addWidget(self.label_line)
        self.spinBox_line = QtWidgets.QSpinBox(self.layoutWidget)
        font = QtGui.QFont()
        font.setPointSize(13)
        self.spinBox_line.setFont(font)
        self.spinBox_line.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.spinBox_line.setMinimum(0)
        self.spinBox_line.setMaximum(20)
        self.spinBox_line.setObjectName("spinBox_line")
        self.horizontalLayout.addWidget(self.spinBox_line)
        self.Button_elli = QtWidgets.QPushButton(Dialog_graphic)
        self.Button_elli.setGeometry(QtCore.QRect(1020, 70, 113, 32))
        self.Button_elli.setObjectName("Button_elli")
        self.Button_Pory = QtWidgets.QPushButton(Dialog_graphic)
        self.Button_Pory.setGeometry(QtCore.QRect(1020, 110, 113, 32))
        self.Button_Pory.setObjectName("Button_Pory")
        self.layoutWidget1 = QtWidgets.QWidget(Dialog_graphic)
        self.layoutWidget1.setGeometry(QtCore.QRect(1030, 370, 111, 26))
        self.layoutWidget1.setObjectName("layoutWidget1")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.layoutWidget1)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.label = QtWidgets.QLabel(self.layoutWidget1)
        self.label.setObjectName("label")
        self.horizontalLayout_2.addWidget(self.label)
        self.spinBox_z = QtWidgets.QSpinBox(self.layoutWidget1)
        self.spinBox_z.setMinimum(-10)
        self.spinBox_z.setMaximum(10)
        self.spinBox_z.setObjectName("spinBox_z")
        self.horizontalLayout_2.addWidget(self.spinBox_z)
        self.widget = QtWidgets.QWidget(Dialog_graphic)
        self.widget.setGeometry(QtCore.QRect(1030, 320, 132, 26))
        self.widget.setObjectName("widget")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget)
        self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.label_2 = QtWidgets.QLabel(self.widget)
        self.label_2.setObjectName("label_2")
        self.horizontalLayout_3.addWidget(self.label_2)
        self.doubleSpinBox_scale = QtWidgets.QDoubleSpinBox(self.widget)
        self.doubleSpinBox_scale.setDecimals(2)
        self.doubleSpinBox_scale.setMinimum(0.1)
        self.doubleSpinBox_scale.setMaximum(10.0)
        self.doubleSpinBox_scale.setSingleStep(0.1)
        self.doubleSpinBox_scale.setProperty("value", 1.0)
        self.doubleSpinBox_scale.setObjectName("doubleSpinBox_scale")
        self.horizontalLayout_3.addWidget(self.doubleSpinBox_scale)

        self.retranslateUi(Dialog_graphic)
        QtCore.QMetaObject.connectSlotsByName(Dialog_graphic)

    def retranslateUi(self, Dialog_graphic):
        _translate = QtCore.QCoreApplication.translate
        Dialog_graphic.setWindowTitle(_translate("Dialog_graphic", "Dialog"))
        self.pushButton_rect.setText(_translate("Dialog_graphic", "四角形"))
        self.pushButton_rotate.setText(_translate("Dialog_graphic", "回転"))
        self.pushButton_linecolor.setText(_translate("Dialog_graphic", "線の色"))
        self.pushButton_fillcolor.setText(_translate("Dialog_graphic", "面の色"))
        self.label_line.setText(_translate("Dialog_graphic", "線幅"))
        self.Button_elli.setText(_translate("Dialog_graphic", "円形"))
        self.Button_Pory.setText(_translate("Dialog_graphic", "多角形"))
        self.label.setText(_translate("Dialog_graphic", "Z深度"))
        self.label_2.setText(_translate("Dialog_graphic", "拡大縮小"))

test_graph_dialog_up05.py
import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from ui_test_Dialog01 import Ui_Dialog_graphic


class Test (QWidget):
    def __init__(self, parent=None):
        super (Test, self).__init__ (parent)
        self.setWindowFlags(
            Qt.Window | Qt.CustomizeWindowHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint)
        self.ui = Ui_Dialog_graphic()
        self.ui.setupUi (self)
        self.scene = QGraphicsScene()
        self.ui.graphicsView.setScene(self.scene)

        #線色の初期設定 StyleSheetで
        self.line_col = QColor('black')
        self.ui.frame_linecolor.setStyleSheet("QWidget { background-color: black }")

        #塗り色の初期設定 paletteで
        self.fill_col = QColor('white')
        pal = self.ui.frame_fillcolor.palette()
        pal.setColor(QPalette.Background,Qt.white)
        self.ui.frame_fillcolor.setAutoFillBackground(True)
        self.ui.frame_fillcolor.setPalette(pal)

        #signal & slot
        self.ui.pushButton_rect.clicked.connect(self.addBOX)
        self.ui.Button_elli.clicked.connect(self.addElli)
        self.ui.Button_Pory.clicked.connect(self.addPory)
        self.ui.pushButton_rotate.clicked.connect(self.rotate)
        self.ui.doubleSpinBox_scale.valueChanged.connect(self.scale)
        self.ui.pushButton_linecolor.clicked.connect(self.linecolor)
        self.ui.pushButton_fillcolor.clicked.connect(self.fillcolor)
        self.ui.spinBox_line.valueChanged.connect(self.setlinewidth)
        self.ui.spinBox_z.valueChanged.connect(self.setZvalue)
        self.scene.selectionChanged.connect(self.item_selectChanged)

        #penの設定
        self.pen = QPen(Qt.SolidLine)
        self.pen.setColor(Qt.black)
        self.linewidth = 5
        self.pen.setWidth(self.linewidth)
        self.pen.setCapStyle(Qt.FlatCap)
        self.pen.setJoinStyle(Qt.MiterJoin)

        #QGraphicsItemの初期化
        self.rect = None
        self.ellipse = None
        self.polygon = None


    def item_selectChanged(self):
        self.ui.doubleSpinBox_scale.setValue(1.0)
        width = self.linewidth
        self.ui.spinBox_line.setValue(width)
        self.pen.setWidth(self.linewidth)

        item = self.selectedItem()

        if item:
            item.setBrush(self.fill_col)
            item.setPen(self.pen)


    def setZvalue(self):
        for item in self.scene.items():
            if item.isSelected() == True:
                item.setZValue(self.ui.spinBox_z.value())
            else:
                pass

    def linecolor(self):
        col = QColorDialog.getColor()

        if col.isValid():
            self.line_col = col
            self.ui.frame_linecolor.setStyleSheet("QWidget { background-color: %s }" % self.line_col.name())

            item = self.selectedItem()
            if item:
                self.pen.setColor(self.line_col)
                item.setPen(self.pen)


    def fillcolor(self):
        col = QColorDialog.getColor()
        if self.fill_col.isValid():
            self.fill_col = col
            self.ui.frame_fillcolor.setStyleSheet("QWidget { background-color: %s }" % self.fill_col.name())

            item = self.selectedItem()
            if item:
                item.setBrush(self.fill_col)


    def setlinewidth(self):
        self.linewidth = self.ui.spinBox_line.value()

        self.pen.setColor(self.line_col)
        self.pen.setWidth(self.linewidth)

        item = self.selectedItem()

        if item:
            item.setBrush(self.fill_col)
            item.setPen(self.pen)
            self.linewidth = self.ui.spinBox_line.value()
            self.pen.setWidth(self.linewidth)
            item.setPen(self.pen)


    def addBOX(self):

        self.rect = QGraphicsRectItem(0, 0, 240, 240)
        self.scene.addItem(self.rect)
        self.rect.setFlag(QGraphicsItem.ItemIsSelectable)
        self.rect.setFlag(QGraphicsItem.ItemIsMovable)
        self.rect.setFlag(QGraphicsItem.ItemIsFocusable)

        self.pen.setColor(self.line_col)
        self.rect.setBrush(self.fill_col)
        self.rect.setPen(self.pen)

    def addElli(self):

        self.ellipse = QGraphicsEllipseItem(0,0,240,240)
        self.scene.addItem(self.ellipse)
        self.ellipse.setFlag(QGraphicsItem.ItemIsSelectable)
        self.ellipse.setFlag(QGraphicsItem.ItemIsMovable)
        self.ellipse.setFlag(QGraphicsItem.ItemIsFocusable)

        self.pen.setColor(self.line_col)
        self.ellipse.setBrush(self.fill_col)
        self.ellipse.setPen(self.pen)


    def addPory(self):
        mypoly = QPolygonF([
            QPointF(80, 0),     # 1
            QPointF(160, 0),    # 2
            QPointF(160, 80),   # 3
            QPointF(240, 80),   # 4
            QPointF(240, 160),  # 5
            QPointF(160, 160),  # 6
            QPointF(160, 240),  # 7
            QPointF(80, 240),   # 8
            QPointF(80, 160),   # 9
            QPointF(0, 160),    # 10
            QPointF(0, 80),     # 11
            QPointF(80, 80)     # 12
        ])

        self.polygon = QGraphicsPolygonItem(mypoly)
        self.scene.addItem(self.polygon)
        self.polygon.setFlag(QGraphicsItem.ItemIsSelectable)
        self.polygon.setFlag(QGraphicsItem.ItemIsMovable)
        self.polygon.setFlag(QGraphicsItem.ItemIsFocusable)

        self.pen.setColor(self.line_col)
        self.polygon.setBrush(self.fill_col)
        self.polygon.setPen(self.pen)


    def rotate(self):

        item = self.selectedItem()

        if item:

            centerX = item.boundingRect().width() / 2
            centerY = item.boundingRect().height() / 2
            item.setTransformOriginPoint(centerX , centerY)
            item.setRotation(item.rotation() + 30)

    def scale(self):
        rate = self.ui.doubleSpinBox_scale.value()
        if rate <= 0.0:
            return

        item = self.selectedItem()
        if item:

            centerX = item.boundingRect().width() / 2
            centerY = item.boundingRect().height() / 2
            item.setTransformOriginPoint(centerX, centerY)

            item.setScale(rate)

            self.linewidth = self.ui.spinBox_line.value()
            self.pen.setWidth(self.linewidth)
            item.setBrush(self.fill_col)
            item.setPen(self.pen)


    def selectedItem(self):
        items = self.scene.selectedItems()
        if len(items) == 1:
            return items[0]
        return None



if __name__ == '__main__':
    app = QApplication (sys.argv)
    path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'icon_2.png')
    app.setWindowIcon(QIcon(path))

    window = Test ()
    window.show ()
    sys.exit (app.exec_ ())

いろんなことができるんでしょうが、2Dは難しいです。

ソースについて少々解説します。
setWindowFlagsはWindowをDialog風にしたりと手動でWindowのスタイルを決めることのできるメソッドです。
別に、Qt Designerで画面作っているなら設定する必要がないように思いますが、Macの最新版のOSの場合、普通に画面を作ると以下のように余計なものがついてきます。
スクリーンショット 2018-07-07 11.33.45.png
タイトルバーの下にタイトルバーみたいなものが、これはっきり言って邪魔です。setWindowFlagsを設定することでこれは消えます。

selectedItemはselectedItemsで選択されているitemの先頭を返します。
ソースでは、複数選択を許していないので、選択されているitemそのものが返却されます。

回転も拡大も以下のコードで選択itemの中心座標を取得します。
centerX = item.boundingRect().width() / 2
centerY = item.boundingRect().height() / 2

setTransformOriginPointによってitem座標に変換の原点を設定します

83
83
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
83
83