とりあえず出来た( ´∀`)
- ベクタパス作成ツール
- 前に作ったベジェ操作ウィジェットの発展型で、割とうまく出来た
ポイント追加と端点操作が自由に出来てデータの保存・読込も出来る

import sys , os , pickle
from PyQt5.QtWidgets import QApplication, QWidget,QMessageBox,QMenu,QAction
from PyQt5.QtCore import QPointF ,QRectF ,Qt
from PyQt5.QtGui import QPainterPath ,QPainter ,QPen,QCursor
class makepath(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('hogetta')
self.setGeometry( 500, 50 , 500 , 500 )
self.setMouseTracking (True)
self.plist=[]
self.plist.append( QPointF(10,250) )
self.plist.append( QPointF(100,100) )
self.plist.append( QPointF(300,200) )
self.plist.append( QPointF(490,250) )
self.a = QPointF(4,4)
self.pselected = -1
self.pmove = 0
self.drawp=0
self.isclosed=0
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect( self.custommenu )
self.show()
def custommenu(self):
menu=QMenu(self)
action = QAction('Add Point', self)
action.triggered.connect(self.addpoint)
menu.addAction(action)
action = QAction('Close Path', self)
action.triggered.connect(self.closepath)
menu.addAction(action)
action = QAction('Open Path', self)
action.triggered.connect(self.openpath)
menu.addAction(action)
action = QAction('Save Path', self)
action.triggered.connect(self.topickle)
menu.addAction(action)
action = QAction('Load Path', self)
action.triggered.connect(self.frompickle)
menu.addAction(action)
menu.exec_(QCursor.pos ())
def addpoint(self):
e=self.mapFromGlobal( QCursor.pos() )
p = QPointF( (e.x() - self.plist[-1].x())/3 , (e.y() - self.plist[-1].y())/3 )
self.plist.append( self.plist[-1] + p )
self.plist.append( self.plist[-1] + p )
self.plist.append( self.plist[-1] + p )
self.update()
def closepath(self):
self.plist[-1] = self.plist[0]
self.isclosed=1
self.update()
def openpath(self):
self.isclosed=0
def topickle(self):
fname=os.path.join(os.path.dirname(__file__) , 'hoge')
with open( fname, 'wb') as f :
pickle.dump( self.plist ,f)
def frompickle(self):
fname=os.path.join(os.path.dirname(__file__) , 'hoge')
with open( fname, 'rb') as f :
self.plist=pickle.load( f)
self.update()
def mouseMoveEvent(self ,e):
if self.pmove :
if self.isclosed and self.pselected==0 :
self.plist[-1]=e.pos()
if e. modifiers().__eq__(Qt.ShiftModifier):
if self.drawp > self.pselected :
self.plist[self.drawp+1]=self.plist[self.drawp]+(self.plist[self.drawp]-self.plist[self.pselected])
elif self.drawp < self.pselected :
self.plist[self.drawp-1]=self.plist[self.drawp]+(self.plist[self.drawp]-self.plist[self.pselected])
else:
self.plist[self.drawp+1] += ( e.pos() - self.plist[self.pselected])
self.plist[self.drawp-1] += ( e.pos() - self.plist[self.pselected])
self.plist[self.pselected] = e.pos()
self.update()
else:
self.pselected = -1
rc = QRectF ( e.pos() - self.a , e.pos() + self.a )
for i,l in enumerate( self.plist) :
if rc.contains( l ) :
self.pselected = i
self.drawp = int( (i+1) / 3 )*3
self.update()
self.setWindowTitle('dawp {} selected {}'.format(self.drawp,self.pselected))
break
def mousePressEvent(self ,e):
if e. modifiers().__eq__(Qt.ControlModifier):
self.addpoint()
elif self.pselected != -1 :
self.pmove = True
def mouseReleaseEvent(self ,e):
self.pmove = False
self.pselected = -1
def paintEvent (self,e):
path = QPainterPath( self.plist[0] )
for i in range (1, len(self.plist) ,3):
path.cubicTo( self.plist[i] , self.plist[i+1] , self.plist[i+2] )
painter= QPainter()
painter.begin(self)
painter.setPen( QPen( Qt.black , 2, style=Qt.SolidLine ) )
painter.drawPath(path)
for i in range( 0 , len(self.plist)-3 , 3 ) :
painter.drawRect( QRectF(QPointF(self.plist[i]-self.a) ,
QPointF(self.plist[i] + self.a) ))
painter.setPen( QPen( Qt.red , 2, style=Qt.DotLine ) )
painter.drawRect( QRectF(QPointF(self.plist[self.drawp]-self.a) ,
QPointF(self.plist[self.drawp] + self.a) ))
if self.drawp==0:
painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp+1] )
painter.drawRect( QRectF(QPointF(self.plist[self.drawp+1]-self.a) ,
QPointF(self.plist[self.drawp+1] + self.a) ))
painter.drawLine( self.plist[-1] , self.plist[-2] )
painter.drawRect( QRectF(QPointF(self.plist[self.drawp-2]-self.a) ,
QPointF(self.plist[self.drawp-2] + self.a) ))
elif self.drawp== len(self.plist)-1 :
painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp-1] )
painter.drawRect( QRectF(QPointF(self.plist[self.drawp-1]-self.a) ,
QPointF(self.plist[self.drawp-1] + self.a) ))
else :
painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp-1] )
painter.drawLine( self.plist[self.drawp] , self.plist[self.drawp+1] )
painter.drawRect( QRectF(QPointF(self.plist[self.drawp+1]-self.a) ,
QPointF(self.plist[self.drawp+1] + self.a) ))
painter.drawRect( QRectF(QPointF(self.plist[self.drawp-1]-self.a) ,
QPointF(self.plist[self.drawp-1] + self.a) ))
if self.pselected != -1 :
painter.setPen( QPen( Qt.blue , 2, style=Qt.DotLine ) )
painter.drawRect( QRectF(QPointF(self.plist[self.pselected]-self.a) ,
QPointF(self.plist[self.pselected] + self.a) ))
painter.end()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = makepath()
sys.exit(app.exec_())
- パスは全てcubu、ベジェに統一した
- コントロールポイントはシフトキーでシンメトリに動く。基点はシフトキーで二つのコントロールポイントと平行に動く
ただし始点と終点の動作はすっきりしてない
この部分は今後の仕様も含めてしっかり考えた方が良いのかもしれない
- 描画ルーチンがゴテゴテしてる、分岐が多すぎ、もっとすっきりさせたい
- picklesのデータ保存は凄く簡単だったが、データに名前はつけれないんだろうか?
- パスの派生クラスを作れば複数パスを並列して処理できそうだが??
- 現在のポイント追加は常に終点に加える形だが、途中に追加できるようにしたい
ベジェの演算が必要になるんだろうか???
--> PyQt でベクターオブジェクト作成ツールを作る # もくじ
コメント(0)