예제 #1
0
	def actually_show_text(self, data):
		text_item = QGraphicsTextItem()
		text_item.setZValue(5)
		if len(data) >= 8 and data[7] != None:
			text_item.setDefaultTextColor(QColor(data[7]))
		else:
			text_item.setDefaultTextColor(QColor("#FFFFFF"))

		text_item.setX(data[2])
		text_item.setY(data[3])
		text_item.setTextWidth(data[4])
		text_item.setPlainText(data[5])

		temp_font = text_item.font()
		temp_font.setPointSize(data[6])
		text_item.setFont(temp_font)

		self.addItem(text_item)
		self.texts[data[1]] = text_item
		self.call_next_action()
예제 #2
0
class Video(QMainWindow):
    def __init__(self):
        super(Video, self).__init__()
        self.resize(1920, 1080)
        # ITEM
        self._item = QGraphicsVideoItem()
        self._textItem = QGraphicsTextItem()
        self._view = QGraphicsView()
        self._scene = QGraphicsScene()
        self._view.resize(1920, 1080)
        self._view.setScene(self._scene)
        self._scene.addItem(self._item)
        self._scene.addItem(self._textItem)
        self._textItem.setPlainText('SRT TEXT')
        self._textItem.setDefaultTextColor(Qt.red)
        font = self._textItem.font()
        font.setPixelSize(50)
        self._textItem.setFont(font)
        self._view.show()
        self._item.setSize(QSizeF(1920, 1080))
        self._player = QMediaPlayer(self)
        self._player.setMedia(
            QMediaContent(
                QUrl.fromLocalFile(
                    '/Users/huangkai/Documents/PycharmProjects/AllTest/Qt插入背景/AddVideos/Videos/yellow.mov'
                )))
        self._player.setVideoOutput(self._item)
        self._player.play()
        self.setCentralWidget(self._view)
        self._item.setPos(400, 500)
        # BUTTON
        self._btn = QPushButton(self)
        self._btn.resize(100, 50)
        self._btn.move(500, 500)
        self._btn.setText('test')
        self._btn.clicked.connect(self._change_text)

    def _change_text(self):
        self._textItem.setPlainText('Fighting')
예제 #3
0
 def _setBold(label: QGraphicsTextItem, isBold: bool) -> None:
     originalFontCopy = label.font()
     originalFontCopy.setBold(isBold)
     label.setFont(originalFontCopy)
예제 #4
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.player = QMediaPlayer(self)  #创建视频播放器
        self.player.setNotifyInterval(1000)  #信息更新周期, ms

        scene = QGraphicsScene(self)
        self.ui.graphicsView.setScene(scene)

        self.videoItem = QGraphicsVideoItem()  #视频显示画面
        self.videoItem.setSize(QSizeF(320, 220))
        self.videoItem.setFlag(QGraphicsItem.ItemIsMovable)
        self.videoItem.setFlag(QGraphicsItem.ItemIsSelectable)
        self.videoItem.setFlag(QGraphicsItem.ItemIsFocusable)

        scene.addItem(self.videoItem)
        self.player.setVideoOutput(self.videoItem)  #设置视频显示图形项

        self.textItem = QGraphicsTextItem("面朝大海,春暖花开")  #弹幕文字
        font = self.textItem.font()
        font.setPointSize(20)
        self.textItem.setFont(font)
        self.textItem.setDefaultTextColor(Qt.red)
        self.textItem.setPos(100, 220)
        self.textItem.setFlag(QGraphicsItem.ItemIsMovable)
        self.textItem.setFlag(QGraphicsItem.ItemIsSelectable)
        self.textItem.setFlag(QGraphicsItem.ItemIsFocusable)
        scene.addItem(self.textItem)

        self.ui.btnText.setCheckable(True)  #弹幕文字按钮
        self.ui.btnText.setChecked(True)

        self.__duration = ""
        self.__curPos = ""
        self.player.stateChanged.connect(self.do_stateChanged)
        self.player.positionChanged.connect(self.do_positionChanged)
        self.player.durationChanged.connect(self.do_durationChanged)

##  ==============自定义功能函数========================

##  ==============event处理函数==========================

    def closeEvent(self, event):  #窗体关闭时
        # 窗口关闭时不能自动停止播放,需手动停止
        if (self.player.state() == QMediaPlayer.PlayingState):
            self.player.stop()

##  ==========由connectSlotsByName()自动连接的槽函数============

    @pyqtSlot()  ##打开文件
    def on_btnOpen_clicked(self):
        curPath = QDir.currentPath()  #获取系统当前目录
        ##      curPath=os.getcwd()
        title = "选择视频文件"
        filt = "视频文件(*.wmv *.avi);;所有文件(*.*)"
        fileName, flt = QFileDialog.getOpenFileName(self, title, curPath, filt)

        if (fileName == ""):
            return

        fileInfo = QFileInfo(fileName)
        baseName = fileInfo.fileName()
        ##      baseName=os.path.basename(fileName)
        self.ui.LabCurMedia.setText(baseName)
        curPath = fileInfo.absolutePath()
        QDir.setCurrent(curPath)  #重设当前目录

        media = QMediaContent(QUrl.fromLocalFile(fileName))

        self.player.setMedia(media)  #设置播放文件
        self.player.play()

    @pyqtSlot()  ##播放
    def on_btnPlay_clicked(self):
        self.player.play()

    @pyqtSlot()  ##暂停
    def on_btnPause_clicked(self):
        self.player.pause()

    @pyqtSlot()  ##停止
    def on_btnStop_clicked(self):
        self.player.stop()

    @pyqtSlot()  ##全屏
    def on_btnFullScreen_clicked(self):
        self.videoWidget.setFullScreen(True)

    @pyqtSlot()  ##静音按钮
    def on_btnSound_clicked(self):
        mute = self.player.isMuted()
        self.player.setMuted(not mute)
        if mute:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/volumn.bmp"))
        else:
            self.ui.btnSound.setIcon(QIcon(":/icons/images/mute.bmp"))

    @pyqtSlot(int)  ##音量调节
    def on_sliderVolumn_valueChanged(self, value):
        self.player.setVolume(value)

    @pyqtSlot(int)  ##播放进度调节
    def on_sliderPosition_valueChanged(self, value):
        self.player.setPosition(value)

    @pyqtSlot()  ##放大
    def on_btnZoomIn_clicked(self):
        sc = self.videoItem.scale()
        self.videoItem.setScale(sc + 0.1)

    @pyqtSlot()  ##缩小
    def on_btnZoomOut_clicked(self):
        sc = self.videoItem.scale()
        self.videoItem.setScale(sc - 0.1)

    @pyqtSlot(bool)  ##弹幕
    def on_btnText_clicked(self, checked):
        self.textItem.setVisible(checked)

##  =============自定义槽函数===============================

    def do_stateChanged(self, state):
        isPlaying = (state == QMediaPlayer.PlayingState)

        self.ui.btnPlay.setEnabled(not isPlaying)
        self.ui.btnPause.setEnabled(isPlaying)
        self.ui.btnStop.setEnabled(isPlaying)

    def do_durationChanged(self, duration):
        self.ui.sliderPosition.setMaximum(duration)

        secs = duration / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__duration = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)

    def do_positionChanged(self, position):
        if (self.ui.sliderPosition.isSliderDown()):
            return  #如果正在拖动滑条,退出

        self.ui.sliderPosition.setSliderPosition(position)

        secs = position / 1000  #秒
        mins = secs / 60  #分钟
        secs = secs % 60  #余数秒
        self.__curPos = "%d:%d" % (mins, secs)
        self.ui.LabRatio.setText(self.__curPos + "/" + self.__duration)
예제 #5
0
class Scene_Base(QGraphicsScene):
	def __init__(self, window):
		super().__init__()
		self.setSceneRect(0, 0, window.game_width, window.game_height)
		self.window = window
		self.init_fields()
		self.create_fade()
		self.dialog_box = None
		self.setup()

	def init_fields(self):
		self.actions = []
		self.current_action = -1
		self.dialog_box = None
		self.target_text = None
		self.current_dialog_text = None
		self.current_dialog_text_offset = 0
		self.background = None
		self.fading_box = None
		self.fade_dir = 0
		self.next_scene = None
		self.buttons = []
		self.current_id = 1
		self.texts = {}
		self.images = {}
		self.moving_images = []
		self.updatable_images = []
		self.vaxx = None
		self.entry = None
		self.pathogen = None
		self.tempPic = None

	def create_fade(self, opc=1):
		self.fading_box = QGraphicsRectItem(0, 0, self.width(), self.height())
		self.fading_box.setBrush(QColor(0, 0, 0))
		self.fading_box.setOpacity(opc)
		self.fading_box.setZValue(100)
		self.addItem(self.fading_box)

	# ==============================================
	# * Setup
	#
	# Overwrite with child classes to add actions.
	# ==============================================

	def setup(self):
		pass

	# ==============================================
	# * Update
	#
	# Updates the scene. Handles input, waiting, etc.
	# ==============================================

	def update(self):
		self.update_fade()
		self.update_dialog()
		self.update_dialog_text()
		self.update_moving_images()
		self.update_animated_images()

	def update_fade(self):
		if self.fading_box is not None:
			if self.fade_dir == 0 and self.fading_box.opacity() > 0:
				self.fading_box.setOpacity(self.fading_box.opacity() - 0.02)
				if self.fading_box.opacity() <= 0:
					self.removeItem(self.fading_box)
					self.fading_box = None
			elif self.fade_dir == 1 and self.fading_box.opacity() < 1:
				self.fading_box.setOpacity(self.fading_box.opacity() + 0.02)
				if self.fading_box.opacity() >= 1:
					if self.next_scene is not None:
						self.window.goto_scene(self.next_scene)
					else:
						self.actually_close_game()

	def update_dialog(self):
		if self.dialog_box is not None:
			if self.dialog_box.opacity() < 0.5:
				self.dialog_box.setOpacity(self.dialog_box.opacity() + 0.04)
				if self.dialog_box.opacity() >= 0.5:
					self.dialog_box.setOpacity(0.5)
					if self.actions[0][0] == 0:
						self.actually_show_dialog(self.actions[0])

	def update_dialog_text(self):
		if self.current_dialog_text is not None:
			curr_text = self.current_dialog_text.toPlainText()
			if curr_text != self.target_text:
				if self.current_dialog_text_offset < 3:
					self.current_dialog_text_offset += 1
				else:
					self.current_dialog_text_offset = 0
					self.current_dialog_text.setPlainText(self.target_text[:len(curr_text) + 1])

	def update_moving_images(self):
		if len(self.moving_images) > 0:
			index = 0
			new_data = []
			for image in self.moving_images:
				pic_id = image[0]
				item = self.images[pic_id]
				item.setX(item.x() + image[1])
				item.setY(item.y() + image[2])
				image[3] -= 1
				if image[3] > 0:
					new_data.append(image)
				elif image[4] is not None:
					image[4]()
				index += 1

			self.moving_images = new_data

	def update_animated_images(self):
		if len(self.updatable_images) > 0:
			index = 0
			for image in self.updatable_images:
				image[2] += 1
				if image[2] > image[4]:
					image[2] = 0
					image[3] += 1
					if image[3] >= len(image[1]):
						image[3] = 0
					image[0].setPixmap(QPixmap(image[1][image[3]]))


	# ==============================================
	# * Mouse Events
	#
	# Handle mouse input.
	# ==============================================

	def mouseMoveEvent(self, mouseEvent):
		pass

	def mousePressEvent(self, mouseEvent):
		self.when_mouse_pressed(mouseEvent)

	def mouseDoubleClickEvent(self, mouseEvent):
		self.when_mouse_pressed(mouseEvent)

	def when_mouse_pressed(self, mouseEvent):
		if self.current_action == 0 and mouseEvent.button() == 1:
			if self.current_dialog_text is not None:
				if self.current_dialog_text.toPlainText() != self.target_text:
					self.current_dialog_text.setPlainText(self.target_text)
				else:
					self.removeItem(self.current_dialog_text)
					self.call_next_action()
		else:
			super(Scene_Base, self).mousePressEvent(mouseEvent)

	# ==============================================
	# * Action Management
	# ==============================================

	def finish_action(self):
		if len(self.actions) > 0:
			self.actions.pop(0)
		else:
			self.wait_for_button_press()

	def check_if_first(self):
		if len(self.actions) == 1:
			self.perform_next_action()

	def perform_next_action(self):
		if len(self.actions) > 0:
			action = self.actions[0]
			self.current_action = action_type = action[0]

			if action_type is -1:
				self.actually_hide_dialog_box()
			elif action_type is 0:
				self.actually_show_dialog(action)
			elif action_type is 1:
				self.actually_show_button(action)
			elif action_type is 2:
				self.actually_set_background(action)
			elif action_type is 3:
				self.actually_goto_scene(action)
			elif action_type is 4:
				self.actually_close_game()
			elif action_type is 5:
				self.actually_play_song(action)
			elif action_type is 6:
				self.actually_wait_for_button_press()
			elif action_type is 7:
				self.actually_remove_all_buttons()
			elif action_type is 8:
				self.actually_show_text(action)
			elif action_type is 9:
				self.actually_hide_text(action)
			elif action_type is 10:
				self.actually_show_image(action)
			elif action_type is 11:
				self.actually_hide_image(action)
			elif action_type is 12:
				self.actually_move_image(action)
			elif action_type is 50:
				self.actually_play_sound(action)

	def call_next_action(self):
		self.finish_action()
		self.perform_next_action()

	# ==============================================
	# * Actual Implementations
	# ==============================================

	def actually_show_dialog(self, data):
		if self.dialog_box is None:
			self.create_dialog_box()
		else:
			self.current_dialog_text = QGraphicsTextItem()
			self.current_dialog_text.setZValue(20)
			self.current_dialog_text.setDefaultTextColor(QColor(255, 255, 255))

			temp_font = self.current_dialog_text.font()
			temp_font.setPointSize(data[2])
			self.current_dialog_text.setFont(temp_font)

			self.addItem(self.current_dialog_text)
			self.current_dialog_text.setX(self.dialog_box.x() + 10)
			self.current_dialog_text.setY(self.dialog_box.y() + 10)
			self.current_dialog_text.setTextWidth(self.dialog_box.boundingRect().width() - 20)

			self.target_text = data[1]
			self.current_dialog_text_offset = 0

	def create_dialog_box(self):
		self.dialog_box = QGraphicsRectItem(0, 0, self.width() - 20, self.height() / 4)
		self.dialog_box.setBrush(QColor(0, 0, 0))
		self.dialog_box.setX(10)
		self.dialog_box.setY(self.height() - self.dialog_box.boundingRect().height() - 10)
		self.dialog_box.setZValue(15);
		self.dialog_box.setOpacity(0)
		self.addItem(self.dialog_box)

	def actually_hide_dialog_box(self):
		if self.dialog_box is not None:
			self.removeItem(self.dialog_box)
			self.dialog_box = None

	def actually_show_button(self, data):
		button = Button(self, data[3], data[4], data[5], data[6], data[7], data[8], data[9])
		button.setX(data[1])
		button.setY(data[2])
		self.buttons.append(button)
		self.addItem(button)
		self.call_next_action()

	def actually_set_background(self, data):
		if self.background is not None:
			self.removeItem(self.background)
			self.background = None

		self.background = QGraphicsPixmapItem(QPixmap(data[1]).scaled(self.window.game_width, self.window.game_height))
		self.background.setZValue(-10)
		self.addItem(self.background)
		self.call_next_action()

	def actually_goto_scene(self, data):
		self.next_scene = data[1]
		self.fade_dir = 1
		self.create_fade(0)

	def actually_close_game(self):
		self.window.close_game()

	def actually_play_song(self, data):
		AudioPlayer.play_song(data[1])
		self.call_next_action()

	def actually_wait_for_button_press(self):
		self.current_action = -1

	def actually_remove_all_buttons(self):
		for b in self.buttons:
			self.removeItem(b)
		self.buttons = []
		self.call_next_action()

	def actually_show_text(self, data):
		text_item = QGraphicsTextItem()
		text_item.setZValue(5)
		if len(data) >= 8 and data[7] != None:
			text_item.setDefaultTextColor(QColor(data[7]))
		else:
			text_item.setDefaultTextColor(QColor("#FFFFFF"))

		text_item.setX(data[2])
		text_item.setY(data[3])
		text_item.setTextWidth(data[4])
		text_item.setPlainText(data[5])

		temp_font = text_item.font()
		temp_font.setPointSize(data[6])
		text_item.setFont(temp_font)

		self.addItem(text_item)
		self.texts[data[1]] = text_item
		self.call_next_action()

	def actually_hide_text(self, data):
		self.removeItem(self.texts[data[1]])
		self.texts[data[1]] = None
		self.call_next_action()

	def actually_show_image(self, data):
		image = None
		if isinstance(data[2], list):
			image = QGraphicsPixmapItem(QPixmap(data[2][0]))
			self.updatable_images.append([image, data[2], 0, 0, data[5]])
		else:
			image = QGraphicsPixmapItem(QPixmap(data[2]))
		image.setX(data[3])
		image.setY(data[4])
		image.setZValue(0)
		self.addItem(image)
		self.images[data[1]] = image
		self.call_next_action()

	def actually_hide_image(self, data):
		self.removeItem(self.images[data[1]])
		self.images[data[1]] = None
		self.call_next_action()

	def actually_move_image(self, data):
		image_id = data[1]
		image = self.images[image_id]
		duration = data[4]
		x_speed = (data[2] - image.x()) / duration
		y_speed = (data[3] - image.y()) / duration
		callback = self.call_next_action if data[5] else None
		image_data = [image_id, x_speed, y_speed, duration, callback]
		self.moving_images.append(image_data)
		if not data[5]:
			self.call_next_action()

	def actually_play_sound(self, data):
		AudioPlayer.play_sound_effect(data[1])
		self.call_next_action()

	# ==============================================
	# * Setup Calls
	# ==============================================

	def add_call(self, data):
		self.actions.append(data)
		self.check_if_first()

	# ==============================================
	# * Extended Calls
	# ==============================================

	# ==============================================
	# Adds a dialog to the game.
	#
	# Ex:
	#     self.add_dialog("Hello World!")
	# ==============================================
	def add_dialog(self, msg, fontSize=20):
		self.add_call([0, msg, fontSize])

	# ==============================================
	# Hides the dialog box
	#
	# Ex:
	#     self.hide_dialog_box()
	# ==============================================
	def hide_dialog_box(self):
		self.add_call([-1])

	# ==============================================
	# Adds a button to the game.
	# After adding all buttons, be sure to call "self.wait_for_button_press".
	# Check scenes/scene_titlescreen.py for example of "font" and "buttonColors"
	#
	# Ex:
	#     self.add_button(30, 30, 200, 200, "My Button!", self.another_function)
	# ==============================================
	def add_button(self, x, y, w, h, name, action, font=None, buttonColors=None, textColors=None):
		self.add_call([1, x, y, w, h, name, font, buttonColors, textColors, action])

	# ==============================================
	# Sets the current background.
	#
	# Ex:
	#     self.set_background("images/Background1.png")
	# ==============================================
	def set_background(self, path):
		self.add_call([2, path])

	# ==============================================
	# Changes the game to the provided scene.
	#
	# Ex:
	#     self.goto_scene(scenes.my_other_scene.My_Other_Scene)
	# ==============================================
	def goto_scene(self, scene):
		self.add_call([3, scene])

	# ==============================================
	# Closes the game.
	#
	# Ex:
	#     self.close_game()
	# ==============================================
	def close_game(self):
		self.add_call([4])

	# ==============================================
	# Plays a song.
	#
	# Ex:
	#     self.play_song("audio/testmusic2.mp3")
	# ==============================================
	def play_song(self, path):
		self.add_call([5, path])

	# ==============================================
	# Plays a sound effect once.
	#
	# Ex:
	#     self.play_sound("audio/testmusic2.mp3")
	# ==============================================
	def play_sound(self, path):
		self.add_call([50, path])

	# ==============================================
	# Once all buttons are created, this will wait for the player to press one.
	#
	# Ex:
	#     self.wait_for_button_press()
	# ==============================================
	def wait_for_button_press(self):
		self.add_call([6])

	# ==============================================
	# Removes all buttons from the screen.
	#
	# Ex:
	#     self.remove_all_buttons()
	# ==============================================
	def remove_all_buttons(self):
		self.add_call([7])

	# ==============================================
	# Based on the value provided, there is a chance it will return True.
	#
	# Ex:
	#     if self.generate_random_chance(30):
	#		  # there is a 30% chance of this happening
	# 	  else:
	#		  # there is a 70% chance of this happening
	# ==============================================
	def generate_random_chance(self, val):
		return random.randint(0, 100) <= val

	# ==============================================
	# Shows text on the screen (not in dialog).
	# This function returns an ID that can be used in self.hide_text.
	#
	# Ex:
	#     text_id = self.show_text(10, 10, 200, "Hello Screen!", 40, "#FF44CC")
	# ==============================================
	def show_text(self, x, y, w, text, size=30, color=None):
		new_id = self.current_id
		self.current_id += 1
		self.add_call([8, new_id, x, y, w, text, size, color])
		return new_id

	# ==============================================
	# Hides the text connected to the ID.
	#
	# Ex:
	#     self.hide_text(text_id)
	# ==============================================
	def hide_text(self, text_id):
		self.add_call([9, text_id])

	# ==============================================
	# Shows a picture on the screen.
	# This function returns an ID that can be used in other functions.
	#
	# Ex:
	#     pic_id = self.show_picture("images/TestImage1.png", 30, 30)
	#
	# ----------------------------------------------
	#
	# Using an array of strings will create an animation.
	# In that case, the last argument is the frame-change frequency of the animation.
	#
	# Ex:
	#     pic_id = self.show_picture(["images/p1_frame_0.png", "images/p1_frame_1.png"], 100, 100, 30)
	# ==============================================
	def show_picture(self, path, x, y, animation_speed=20):
		new_id = self.current_id
		self.current_id += 1
		self.add_call([10, new_id, path, x, y, animation_speed])
		return new_id

	# ==============================================
	# Removes the picture connected to the provided ID.
	#
	# Ex:
	#     self.hide_picture(pic_id)
	# ==============================================
	def hide_picture(self, image_id):
		self.add_call([11, image_id])

	# ==============================================
	# Moves the picture to new coordinates over a duration of time.
	#
	# Ex:
	#     self.move_picture(pic_id, 90, 30, 120)
	# ==============================================
	def move_picture(self, image_id, x, y, duration, wait_until_finished=True):
		self.add_call([12, image_id, x, y, duration, wait_until_finished])

	#===============================================
	# Sets the vaccination status
	# True/False, 50% chance
	#===============================================
	def set_vaxx(self):
		if self.generate_random_chance(50):
			Scene_Base.vaxx = True
		else:
			Scene_Base.vaxx = False

	#===============================================
	# Sets the entry point
	# 0 is for blood (cut)
	# 1 is for stomach (mouth)
	#===============================================	
	def set_entry(self):
		if self.generate_random_chance(50):
			Scene_Base.entry = 0
		else:
			Scene_Base.entry = 1

	# ==============================================
	# Gets and sets global values
	#
	# Ex:
	#     self.set_value("Health", 100)
	#
	#     self.add_value("Health", -1)
	#
	#     if self.get_value("Health") <= 30:
	#         self.add_dialog("Player is less than 30 health!")
	# ==============================================
			
	def set_value(self, name, value):
		Scene_Base.GLOBAL_VARS[name] = value

	def add_value(self, name, value):
		Scene_Base.GLOBAL_VARS[name] += value

	def get_value(self, name):
		return Scene_Base.GLOBAL_VARS[name]
예제 #6
0
파일: MainWindow.py 프로젝트: jbernalr/FMPy
    def createGraphics(self):
        """ Create the graphical representation of the FMU's inputs and outputs """
        def variableColor(variable):
            if variable.type == 'Real':
                return QColor.fromRgb(0, 0, 127)
            elif variable.type in ['Integer', 'Enumeration']:
                return QColor.fromRgb(255, 127, 0)
            elif variable.type == 'Boolean':
                return QColor.fromRgb(255, 0, 255)
            elif variable.type == 'String':
                return QColor.fromRgb(0, 128, 0)
            else:
                return QColor.fromRgb(0, 0, 0)

        inputVariables = []
        outputVariables = []
        maxInputLabelWidth = 0
        maxOutputLabelWidth = 0

        textItem = QGraphicsTextItem()
        fontMetrics = QFontMetricsF(textItem.font())

        for variable in self.modelDescription.modelVariables:
            if variable.causality == 'input':
                inputVariables.append(variable)
            elif variable.causality == 'output':
                outputVariables.append(variable)

        for variable in inputVariables:
            maxInputLabelWidth = max(maxInputLabelWidth,
                                     fontMetrics.width(variable.name))

        for variable in outputVariables:
            maxOutputLabelWidth = max(maxOutputLabelWidth,
                                      fontMetrics.width(variable.name))

        from math import floor

        scene = QGraphicsScene()
        self.ui.graphicsView.setScene(scene)
        group = QGraphicsItemGroup()
        scene.addItem(group)
        group.setPos(200.5, -50.5)
        lh = 15  # line height

        w = max(150., maxInputLabelWidth + maxOutputLabelWidth + 20)
        h = max(50., 10 + lh * max(len(inputVariables), len(outputVariables)))

        block = QGraphicsRectItem(0, 0, w, h, group)
        block.setPen(QColor.fromRgb(0, 0, 255))

        pen = QPen()
        pen.setWidthF(1)

        font = QFont()
        font.setPixelSize(10)

        # inputs
        y = floor((h - len(inputVariables) * lh) / 2 - 2)
        for variable in inputVariables:
            text = QGraphicsTextItem(variable.name, group)
            text.setDefaultTextColor(QColor.fromRgb(0, 0, 255))
            text.setFont(font)
            text.setX(3)
            text.setY(y)

            polygon = QPolygonF([
                QPointF(-13.5, y + 4),
                QPointF(1, y + 11),
                QPointF(-13.5, y + 18)
            ])

            path = QPainterPath()
            path.addPolygon(polygon)
            path.closeSubpath()
            contour = QGraphicsPathItem(path, group)
            contour.setPen(QPen(Qt.NoPen))
            contour.setBrush(variableColor(variable))

            y += lh

        # outputs
        y = floor((h - len(outputVariables) * lh) / 2 - 2)
        for variable in outputVariables:
            text = QGraphicsTextItem(variable.name, group)
            text.setDefaultTextColor(QColor.fromRgb(0, 0, 255))
            text.setFont(font)
            text.setX(w - 3 - text.boundingRect().width())
            text.setY(y)

            polygon = QPolygonF([
                QPointF(w, y + 0 + 7.5),
                QPointF(w + 7, y + 3.5 + 7.5),
                QPointF(w, y + 7 + 7.5)
            ])

            path = QPainterPath()
            path.addPolygon(polygon)
            path.closeSubpath()
            contour = QGraphicsPathItem(path, group)
            pen = QPen()
            pen.setColor(variableColor(variable))
            pen.setJoinStyle(Qt.MiterJoin)
            contour.setPen(pen)

            y += lh
예제 #7
0
class Block(QGraphicsRectItem):
    """
        Entity-block with text & four connection ports
    """
    def __init__(self, name='Untitled', parent=None):
        super(Block, self).__init__(None)
        self.parent = parent

        w = 60.0
        h = 40.0

        self.__base_color = QColor(158, 94, 155)

        # Properties of the rectangle:
        self.setPen(QtGui.QPen(self.__base_color, 2))
        # self.setPen(QtGui.QPen(QtCore.Qt.blue, 2))
        self.setBrush(QtGui.QBrush(self.__base_color))
        self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
        self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))

        # Label:
        self.label = QGraphicsTextItem(name, self)
        self.label.setFont(QFont())
        self.name = name

        # Create corner for resize:
        self.sizer = HandleItem(self)
        self.sizer.setPos(w, h)
        self.sizer.posChangeCallbacks.append(
            self.changeSize)  # Connect the callback

        self.sizer.setFlag(self.sizer.ItemIsSelectable, True)

        # Inputs and outputs of the block:
        self.ports = []
        self.ports.append(PortItem('a', self))
        self.ports.append(PortItem('b', self))
        self.ports.append(PortItem('c', self))
        self.ports.append(PortItem('d', self))

        # Update size:
        self.changeSize(w, h)

    def get_text(self):
        return self.label.toPlainText()

    def get_random_port(self):
        i = random.randint(0, len(self.ports) - 1)
        if i in range(0, 5):
            return self.ports[i]

    def delete(self):
        msg = QMessageBox()

        msg.setIcon(QMessageBox.Question)
        msg.setText("Вы действительно хотите удалить блок?")
        msg.setInformativeText("Это действие нельзя отменить")
        msg.setWindowTitle("Подтвердите действие")
        msg.setDetailedText("При удалении блока удалятся все его соединения!")

        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

        confirm = msg.exec_()

        if confirm == QMessageBox.Ok:
            self.parent.remove_node(self)

    def edit_parameters(self):
        text, ok = QInputDialog.getText(None,
                                        'Параметры',
                                        'Текст блока:',
                                        text=self.label.toPlainText())
        if ok:
            self.label.setPlainText(text)

    def contextMenuEvent(self, event):
        menu = QMenu()
        action_delete = menu.addAction('Удалить')
        action_params = menu.addAction('Параметры')
        action_delete.triggered.connect(self.delete)
        action_params.triggered.connect(self.edit_parameters)
        menu.exec_(event.screenPos())

    def changeSize(self, w, h):
        """ Resize block function """
        # Limit the block size:

        metric = QFontMetrics(self.label.font())
        width = metric.width(self.name)
        height = metric.height()

        if h < height + 5:
            h = height + 5
        if w < width + 5:
            w = width + 5
        self.setRect(0.0, 0.0, w, h)
        # center label:
        rect = self.label.boundingRect()
        lw, lh = rect.width(), rect.height()
        lx = (w - lw) / 2
        ly = (h - lh) / 2
        self.label.setPos(lx, ly)
        # Update port positions:
        self.ports[0].setPos(0, h / 2)
        self.ports[1].setPos(w / 2, 0)
        self.ports[2].setPos(w, h / 2)
        self.ports[3].setPos(w / 2, h)
        return w, h
예제 #8
0
class LinkItem(QGraphicsObject):
    """
    A Link item in the canvas that connects two :class:`.NodeItem`\s in the
    canvas.

    The link curve connects two `Anchor` items (see :func:`setSourceItem`
    and :func:`setSinkItem`). Once the anchors are set the curve
    automatically adjusts its end points whenever the anchors move.

    An optional source/sink text item can be displayed above the curve's
    central point (:func:`setSourceName`, :func:`setSinkName`)

    """

    #: Z value of the item
    Z_VALUE = 0

    def __init__(self, *args):
        self.__boundingRect = None
        QGraphicsObject.__init__(self, *args)
        self.setFlag(QGraphicsItem.ItemHasNoContents, True)
        self.setAcceptedMouseButtons(Qt.RightButton | Qt.LeftButton)
        self.setAcceptHoverEvents(True)

        self.setZValue(self.Z_VALUE)

        self.sourceItem = None
        self.sourceAnchor = None
        self.sinkItem = None
        self.sinkAnchor = None

        self.curveItem = LinkCurveItem(self)

        self.sourceIndicator = LinkAnchorIndicator(self)
        self.sinkIndicator = LinkAnchorIndicator(self)
        self.sourceIndicator.hide()
        self.sinkIndicator.hide()

        self.linkTextItem = QGraphicsTextItem(self)

        self.__sourceName = ""
        self.__sinkName = ""

        self.__dynamic = False
        self.__dynamicEnabled = False

        self.hover = False

        self.prepareGeometryChange()
        self.__boundingRect = None

    def setSourceItem(self, item, anchor=None):
        """
        Set the source `item` (:class:`.NodeItem`). Use `anchor`
        (:class:`.AnchorPoint`) as the curve start point (if ``None`` a new
        output anchor will be created using ``item.newOutputAnchor()``).

        Setting item to ``None`` and a valid anchor is a valid operation
        (for instance while mouse dragging one end of the link).

        """
        if item is not None and anchor is not None:
            if anchor not in item.outputAnchors():
                raise ValueError("Anchor must be belong to the item")

        if self.sourceItem != item:
            if self.sourceAnchor:
                # Remove a previous source item and the corresponding anchor
                self.sourceAnchor.scenePositionChanged.disconnect(
                    self._sourcePosChanged)

                if self.sourceItem is not None:
                    self.sourceItem.removeOutputAnchor(self.sourceAnchor)

                self.sourceItem = self.sourceAnchor = None

            self.sourceItem = item

            if item is not None and anchor is None:
                # Create a new output anchor for the item if none is provided.
                anchor = item.newOutputAnchor()

            # Update the visibility of the start point indicator.
            self.sourceIndicator.setVisible(bool(item))

        if anchor != self.sourceAnchor:
            if self.sourceAnchor is not None:
                self.sourceAnchor.scenePositionChanged.disconnect(
                    self._sourcePosChanged)

            self.sourceAnchor = anchor

            if self.sourceAnchor is not None:
                self.sourceAnchor.scenePositionChanged.connect(
                    self._sourcePosChanged)

        self.__updateCurve()

    def setSinkItem(self, item, anchor=None):
        """
        Set the sink `item` (:class:`.NodeItem`). Use `anchor`
        (:class:`.AnchorPoint`) as the curve end point (if ``None`` a new
        input anchor will be created using ``item.newInputAnchor()``).

        Setting item to ``None`` and a valid anchor is a valid operation
        (for instance while mouse dragging one and of the link).

        """
        if item is not None and anchor is not None:
            if anchor not in item.inputAnchors():
                raise ValueError("Anchor must be belong to the item")

        if self.sinkItem != item:
            if self.sinkAnchor:
                # Remove a previous source item and the corresponding anchor
                self.sinkAnchor.scenePositionChanged.disconnect(
                    self._sinkPosChanged)

                if self.sinkItem is not None:
                    self.sinkItem.removeInputAnchor(self.sinkAnchor)

                self.sinkItem = self.sinkAnchor = None

            self.sinkItem = item

            if item is not None and anchor is None:
                # Create a new input anchor for the item if none is provided.
                anchor = item.newInputAnchor()

            # Update the visibility of the end point indicator.
            self.sinkIndicator.setVisible(bool(item))

        if self.sinkAnchor != anchor:
            if self.sinkAnchor is not None:
                self.sinkAnchor.scenePositionChanged.disconnect(
                    self._sinkPosChanged)

            self.sinkAnchor = anchor

            if self.sinkAnchor is not None:
                self.sinkAnchor.scenePositionChanged.connect(
                    self._sinkPosChanged)

        self.__updateCurve()

    def setFont(self, font):
        """
        Set the font for the channel names text item.
        """
        if font != self.font():
            self.linkTextItem.setFont(font)
            self.__updateText()

    def font(self):
        """
        Return the font for the channel names text.
        """
        return self.linkTextItem.font()

    def setChannelNamesVisible(self, visible):
        """
        Set the visibility of the channel name text.
        """
        self.linkTextItem.setVisible(visible)

    def setSourceName(self, name):
        """
        Set the name of the source (used in channel name text).
        """
        if self.__sourceName != name:
            self.__sourceName = name
            self.__updateText()

    def sourceName(self):
        """
        Return the source name.
        """
        return self.__sourceName

    def setSinkName(self, name):
        """
        Set the name of the sink (used in channel name text).
        """
        if self.__sinkName != name:
            self.__sinkName = name
            self.__updateText()

    def sinkName(self):
        """
        Return the sink name.
        """
        return self.__sinkName

    def _sinkPosChanged(self, *arg):
        self.__updateCurve()

    def _sourcePosChanged(self, *arg):
        self.__updateCurve()

    def __updateCurve(self):
        self.prepareGeometryChange()
        self.__boundingRect = None
        if self.sourceAnchor and self.sinkAnchor:
            source_pos = self.sourceAnchor.anchorScenePos()
            sink_pos = self.sinkAnchor.anchorScenePos()
            source_pos = self.curveItem.mapFromScene(source_pos)
            sink_pos = self.curveItem.mapFromScene(sink_pos)

            # Adaptive offset for the curve control points to avoid a
            # cusp when the two points have the same y coordinate
            # and are close together
            delta = source_pos - sink_pos
            dist = math.sqrt(delta.x()**2 + delta.y()**2)
            cp_offset = min(dist / 2.0, 60.0)

            # TODO: make the curve tangent orthogonal to the anchors path.
            path = QPainterPath()
            path.moveTo(source_pos)
            path.cubicTo(source_pos + QPointF(cp_offset, 0),
                         sink_pos - QPointF(cp_offset, 0), sink_pos)

            self.curveItem.setPath(path)
            self.sourceIndicator.setPos(source_pos)
            self.sinkIndicator.setPos(sink_pos)
            self.__updateText()
        else:
            self.setHoverState(False)
            self.curveItem.setPath(QPainterPath())

    def __updateText(self):
        self.prepareGeometryChange()
        self.__boundingRect = None

        if self.__sourceName or self.__sinkName:
            if self.__sourceName != self.__sinkName:
                text = u"{0} \u2192 {1}".format(self.__sourceName,
                                                self.__sinkName)
            else:
                # If the names are the same show only one.
                # Is this right? If the sink has two input channels of the
                # same type having the name on the link help elucidate
                # the scheme.
                text = self.__sourceName
        else:
            text = ""

        self.linkTextItem.setPlainText(text)

        path = self.curveItem.path()
        if not path.isEmpty():
            center = path.pointAtPercent(0.5)
            angle = path.angleAtPercent(0.5)

            brect = self.linkTextItem.boundingRect()

            transform = QTransform()
            transform.translate(center.x(), center.y())
            transform.rotate(-angle)

            # Center and move above the curve path.
            transform.translate(-brect.width() / 2, -brect.height())

            self.linkTextItem.setTransform(transform)

    def removeLink(self):
        self.setSinkItem(None)
        self.setSourceItem(None)
        self.__updateCurve()

    def setHoverState(self, state):
        if self.hover != state:
            self.prepareGeometryChange()
            self.__boundingRect = None
            self.hover = state
            self.sinkIndicator.setHoverState(state)
            self.sourceIndicator.setHoverState(state)
            self.curveItem.setHoverState(state)

    def hoverEnterEvent(self, event):
        # Hover enter event happens when the mouse enters any child object
        # but we only want to show the 'hovered' shadow when the mouse
        # is over the 'curveItem', so we install self as an event filter
        # on the LinkCurveItem and listen to its hover events.
        self.curveItem.installSceneEventFilter(self)
        return QGraphicsObject.hoverEnterEvent(self, event)

    def hoverLeaveEvent(self, event):
        # Remove the event filter to prevent unnecessary work in
        # scene event filter when not needed
        self.curveItem.removeSceneEventFilter(self)
        return QGraphicsObject.hoverLeaveEvent(self, event)

    def sceneEventFilter(self, obj, event):
        if obj is self.curveItem:
            if event.type() == QEvent.GraphicsSceneHoverEnter:
                self.setHoverState(True)
            elif event.type() == QEvent.GraphicsSceneHoverLeave:
                self.setHoverState(False)

        return QGraphicsObject.sceneEventFilter(self, obj, event)

    def boundingRect(self):
        if self.__boundingRect is None:
            self.__boundingRect = self.childrenBoundingRect()
        return self.__boundingRect

    def shape(self):
        return self.curveItem.shape()

    def setEnabled(self, enabled):
        """
        Reimplemented from :class:`QGraphicsObject`

        Set link enabled state. When disabled the link is rendered with a
        dashed line.

        """
        # This getter/setter pair override a property from the base class.
        # They should be renamed to e.g. setLinkEnabled/linkEnabled
        self.curveItem.setLinkEnabled(enabled)

    def isEnabled(self):
        return self.curveItem.isLinkEnabled()

    def setDynamicEnabled(self, enabled):
        """
        Set the link's dynamic enabled state.

        If the link is `dynamic` it will be rendered in red/green color
        respectively depending on the state of the dynamic enabled state.

        """
        if self.__dynamicEnabled != enabled:
            self.__dynamicEnabled = enabled
            if self.__dynamic:
                self.__updatePen()

    def isDynamicEnabled(self):
        """
        Is the link dynamic enabled.
        """
        return self.__dynamicEnabled

    def setDynamic(self, dynamic):
        """
        Mark the link as dynamic (i.e. it responds to
        :func:`setDynamicEnabled`).

        """
        if self.__dynamic != dynamic:
            self.__dynamic = dynamic
            self.__updatePen()

    def isDynamic(self):
        """
        Is the link dynamic.
        """
        return self.__dynamic

    def __updatePen(self):
        self.prepareGeometryChange()
        self.__boundingRect = None
        if self.__dynamic:
            if self.__dynamicEnabled:
                color = QColor(0, 150, 0, 150)
            else:
                color = QColor(150, 0, 0, 150)

            normal = QPen(QBrush(color), 2.0)
            hover = QPen(QBrush(color.darker(120)), 2.1)
        else:
            normal = QPen(QBrush(QColor("#9CACB4")), 2.0)
            hover = QPen(QBrush(QColor("#7D7D7D")), 2.1)

        self.curveItem.setCurvePenSet(normal, hover)
예제 #9
0
class LabelItem(QGraphicsRectItem):
    def __init__(self, text='', parent=None):
        super(LabelItem, self).__init__(None)

        self.parent = parent
        self.text = text

        # Properties of the rectangle:
        self.setPen(QtGui.QPen(QtCore.Qt.lightGray))
        self.setBrush(QtGui.QBrush(QColor(234, 193, 72)))
        self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
        self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
        # Label:
        self.label = QGraphicsTextItem(self.text, self)

        metric = QFontMetrics(self.label.font())
        self.width = metric.width(self.text)
        self.height = metric.height()

        self.setRect(0.0, 0.0, self.width + 1, self.height + 1)

    def contextMenuEvent(self, event):
        menu = QMenu()

        pa = menu.addAction('Параметры')
        pa.triggered.connect(self.edit_parameters)

        drop = menu.addAction('Удалить связь')
        drop.triggered.connect(self.remove_connection)

        menu.exec_(event.screenPos())

    def remove_connection(self):
        self.parent.delete_connection()

    def set_text(self, text):
        self.parent.arrow_text = str(text)
        self.text = str(text)
        self.label.setPlainText(text)

        metric = QFontMetrics(self.label.font())
        width = metric.width(self.text)
        height = metric.height()

        if self.height < height + 5:
            self.height = height + 5
        if self.width < width + 5:
            self.width = width + 5
        self.setRect(0.0, 0.0, self.width, self.height)
        # center label:
        rect = self.label.boundingRect()
        lw, lh = rect.width(), rect.height()
        lx = (self.width - lw) / 2
        ly = (self.height - lh) / 2
        self.label.setPos(lx + 1, ly)

    def edit_parameters(self):
        text, ok = QInputDialog.getText(None,
                                        'Параметры',
                                        'Отношение:',
                                        text=self.text)
        if ok:
            self.set_text(text)

    def change_size(self, w, h):
        """ Resize block function """
        # Limit the block size:
        metric = QFontMetrics(self.label.font())
        width = metric.width(self.text)
        height = metric.height()

        if h < height + 5:
            self.height += 5
        if w < width + 5:
            self.width += 5
        self.setRect(0.0, 0.0, self.width, self.height)
        # center label:
        rect = self.label.boundingRect()
        lw, lh = rect.width(), rect.height()
        lx = (w - lw) / 2
        ly = (h - lh) / 2
        self.label.setPos(lx, ly)

        return w, h
예제 #10
0
class ItemConfigDialog(QMainWindow, Ui_MainWindow):
    """
    Окно настроек элемента
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setupUi(self)

        self.text_aligns = [
            ('center', 'По центру'),
            ('left', 'По левому краю'),
            ('right', 'По правому краю'),
        ]
        self.text_align = 'center'

        for align, align_text in self.text_aligns:
            self.textPosH.addItem(align_text)

        self.item: QGraphicsRectItem = QGraphicsRectItem()
        self.main_view: QGraphicsView = QGraphicsView()

        self.fontSelect.currentFontChanged.connect(self.render_text)
        self.fontSize.valueChanged.connect(self.render_text)
        self.textPosH.currentTextChanged.connect(self.render_text)
        self.exText.textChanged.connect(self.render_text)

        self.font_color = QColor('black')

        self.scene = QGraphicsScene()
        self.graphicsView.setScene(self.scene)
        self.text = QGraphicsTextItem()

        self.buttonBox.accepted.connect(self.accepted)

        self.colorPicker.clicked.connect(self.select_color)

    def show(self):
        super(ItemConfigDialog, self).show()
        self.text = QGraphicsTextItem()
        self.name.setText(self.item.toolTip())
        font = QFont()
        font_name = self.item.data(int(const.ITEM_DATA_KEY_FONT))
        if font_name:
            font.fromString(font_name)
            font_size = self.item.data(int(const.ITEM_DATA_KEY_FONT_SIZE))
            if font_size:
                font.setPointSize(font_size)
            else:
                font.setPointSize(12)
            font_color = self.item.data(int(const.ITEM_DATA_KEY_FONT_COLOR))
            if font_color:
                self.font_color.setRgb(*font_color)
            self.text.setFont(font)
        self.text_align = self.item.data(int(const.ITEM_DATA_KEY_FONT_ALIGN))

        self.render_text()
        self.render_item()

    def select_color(self):
        color = QColorDialog.getColor()

        if color.isValid():
            self.font_color = color
            self.render_text()

    def render_text(self, event=None):
        font = self.fontSelect.currentFont()
        font.setPointSize(self.fontSize.value())
        self.text.setFont(font)
        self.text.setTextWidth(self.item.rect().width())
        self.text.setDefaultTextColor(self.font_color)
        for align, align_text in self.text_aligns:
            if align_text == self.textPosH.currentText():
                self.text_align = align

        self.text.setHtml(f"<div align='{self.text_align}'>{self.exText.text()}</div>")

    def render_item(self):
        self.scene.clear()
        pos_from = self.main_view.mapFromScene(self.item.sceneBoundingRect())
        pos = self.main_view.mapToScene(pos_from)
        point = pos.boundingRect()
        width, height = point.width(), point.height()

        img = QImage(width, height, QImage.Format_ARGB32_Premultiplied)
        painter = QPainter(img)
        painter.setRenderHint(QPainter.Antialiasing)
        self.item.scene().render(painter, source=QRectF(point.x(), point.y(), width, height))
        painter.end()

        self.scene.addItem(QGraphicsPixmapItem(QPixmap(img)))
        self.scene.addItem(self.text)
        self.graphicsView.fitInView(QRectF(0, 0, width, height), Qt.KeepAspectRatio)

        self.scene.update()

    def accepted(self):
        self.item.setData(int(const.ITEM_DATA_KEY_FONT), self.text.font().toString().split(',')[0])
        self.item.setData(int(const.ITEM_DATA_KEY_FONT_SIZE), self.text.font().pointSize())
        self.item.setData(int(const.ITEM_DATA_KEY_FONT_ALIGN), self.text_align)
        self.item.setData(int(const.ITEM_DATA_KEY_FONT_COLOR), self.font_color.getRgb())
        self.item.setToolTip(self.name.text())
        self.item.scene().update()
        self.close()