How to safely go through components of QEntity in PyQt5? - python

Here if I run the code with components() line commented out I get a window with a purple torus as expected but if I just call the components() on the torus_entity (uncomment the line) the torus disappears.
I can print the components from the components() but trying to usem them returns an error saying it was deleted, for example: deleted torus_mesh.
The material variable which can be reused for various models also throws error saying the material was deleted if you try to use it on any line beyond the components() call.
Qt documentation: https://doc.qt.io/qt-5/qt3dcore-qentity.html#components
Documentation says components returns a list of QComponent nothing about the deletion, I don't know how to use this properly?
I'd like to go through the components and check them and change their properties, for example change position and/or scale through QTransform component.
I could go down the QT version to 5.12.12 but I don't know how to do this for PyQt5 so it builds against this QT version.
I've tried it in PyQt6, also in Qt5 (c++, but different version then the PyQt5 uses) and it works just fine in both, this might be a bug in PyQt5/Qt5? I wonder if there's a workaround for this (maybe making adjustments in some PyQt5 files?)?
import sys
from PyQt5.Qt3DCore import QEntity, QTransform, QAspectEngine
from PyQt5.QtCore import QPropertyAnimation, QVariant, QUrl
from PyQt5.QtGui import QVector3D, QQuaternion, QGuiApplication, QColor
from PyQt5.Qt3DRender import QCamera, QCameraLens, QRenderAspect, QDirectionalLight, QSceneLoader
from PyQt5.Qt3DInput import QInputAspect
from PyQt5.Qt3DExtras import QForwardRenderer, QMetalRoughMaterial, QCylinderMesh, QSphereMesh, QTorusMesh, \
Qt3DWindow, QOrbitCameraController, QPlaneMesh
def create_scene():
root_entity = QEntity()
d_light_entity = QEntity(root_entity)
direction_light = QDirectionalLight()
direction_light.setColor(QColor(255, 254, 245))
direction_light.setIntensity(2)
d_light_entity.addComponent(direction_light)
material = QMetalRoughMaterial(root_entity)
material.setBaseColor(QColor(160, 30, 160))
material.setRoughness(.5)
# Torus
torus_entity = QEntity(root_entity)
torus_mesh = QTorusMesh()
torus_mesh.setRadius(5)
torus_mesh.setMinorRadius(1)
torus_mesh.setRings(100)
torus_mesh.setSlices(20)
torus_transform = QTransform()
torus_transform.setScale3D(QVector3D(1.5, 1, 0.5))
torus_entity.addComponent(torus_mesh)
torus_entity.addComponent(torus_transform)
torus_entity.addComponent(material)
#components = torus_entity.components()
return root_entity
def main(argv):
app = QGuiApplication(argv)
view = Qt3DWindow()
view.defaultFrameGraph().setClearColor(QColor(39, 39, 39))
scene = create_scene()
camera = view.camera()
camera.lens().setPerspectiveProjection(45.0, 15.0/9.0, .1, 1000.0)
camera.setPosition(QVector3D(0, 0, 40.0))
camera.setViewCenter(QVector3D(0, 0, 0))
view.setRootEntity(scene)
view.show()
return sys.exit(app.exec())
if __name__ == '__main__':
main(sys.argv)

Related

QPixmapCache in PyQt6

Hello I am trying to create a PyQt6 widget that animates over a set of images, but at a precise frame rate that varies as a function of realtime parameters. I insert QPixmaps into the cache within a for loop, and am able to find the QPixmap objects through QPixmap.find() within the same for loop, but outside the loop .find() returns None.
Below is the script. I can include the image series if needed. Appreciate any help.
import sys
from PyQt6.QtWidgets import (
QApplication,
QMainWindow,
QLabel
)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPixmap, QPixmapCache
from pathlib import Path
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.animating_label = QLabel('animation here')
self.animating_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
self.animating_label.pixmap().size().setWidth(200)
self.animating_label.pixmap().size().setHeight(200)
self.setCentralWidget(self.animating_label)
parent_path = Path(__file__).parent
self.images_path = parent_path / 'images/animation_set/'
self.animating_label.setPixmap(QPixmap(self.images_path.__str__() + "/clock01.png"))
self.pixmapcache_keys: [str] = []
self.load_images()
test = QPixmapCache.find("clock02")
try:
self.animating_label.setPixmap(test)
except:
if test == None:
print("Failure: QPixMapCache.find() returned", test)
def load_images(self):
image_suffixes = ['.jpg', '.png', '.gif', '.bmp']
imgs_found_count = 0
for filepath in self.images_path.iterdir():
if filepath.suffix in image_suffixes:
imgs_found_count += 1
cache_key = filepath.stem
self.pixmapcache_keys.append(cache_key)
if not QPixmapCache.find(cache_key):
pixmap = QPixmap(filepath.__str__())
QPixmapCache.insert(cache_key, pixmap)
print("pixmap %s" % cache_key, QPixmapCache.find(cache_key))
print(imgs_found_count, "image(s) found in animation_set directory.", len(self.pixmapcache_keys),
"keys loaded into QPixmapCache")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
# start Qt event loop
app.exec()
print("Script complete.")
sys.exit(1)
Here is the output:
pixmap clock04 <PyQt6.QtGui.QPixmap object at 0x101c84b30>
pixmap clock10 <PyQt6.QtGui.QPixmap object at 0x101c84970>
pixmap clock11 <PyQt6.QtGui.QPixmap object at 0x101c84b30>
pixmap clock05 <PyQt6.QtGui.QPixmap object at 0x101c84970>
...
24 image(s) found in animation_set directory. 24 keys loaded into QPixmapCache
Failure: QPixMapCache.find() returned None
Script complete.
I was able to get the animation working using a list of QPixmaps instead of QPixmapCache, but I am not sure if this is the optimal approach.
Generating Qpixmap list from files:
for filepath in sorted(self.images_path.iterdir()):
if filepath.suffix in image_suffixes:
qpixmap = QPixmap(filepath.__str__())
self.pixmaps.append(qpixmap)
called elsewhere on a timer
def advance(self):
if self.pixmap_current_index >= len(self.pixmaps) - 1:
self.pixmap_current_index = 0
else:
self.pixmap_current_index += 1
self.animating_label.setPixmap(self.pixmaps[self.pixmap_current_index])
self.timer.start(self.refresh_interval)

(PyQt) How can I reset the CharFormat of an entire QTextEdit?

I'm using mergeCharFormat on several words within my QTextEdit, in an effort to highlight them. Something like this:
import sys
from PyQt4 import QtGui, uic
from PyQt4.QtCore import *
def drawGUI():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
w.setGeometry(200, 200, 200, 50)
editBox = QtGui.QTextEdit(w)
text = 'Hello stack overflow, this is a test and tish is a misspelled word'
editBox.setText(text)
""" Now there'd be a function that finds misspelled words """
# Highlight misspelled words
misspelledWord = 'tish'
cursor = editBox.textCursor()
format_ = QtGui.QTextCharFormat()
format_.setBackground(QtGui.QBrush(QtGui.QColor("pink")))
pattern = "\\b" + misspelledWord + "\\b"
regex = QRegExp(pattern)
index = regex.indexIn(editBox.toPlainText(), 0)
cursor.setPosition(index)
cursor.movePosition(QtGui.QTextCursor.EndOfWord, 1)
cursor.mergeCharFormat(format_)
w.showFullScreen()
sys.exit(app.exec_())
if __name__ == '__main__':
drawGUI()
So, this highlighting feature works exactly as intended. However, I can't find a good way to clear the highlights from the textarea. What is a good method of doing such a thing- essentially just setting the char format of the entire QTextEdit back to its defaults?
What I've tried so far is getting the cursor again, and setting its format to a new format with a clear background, then putting the cursor over the entire selection and using QTextCursor.setCharFormat(), but this appears to do nothing.
Applying a new QTextCharFormat to the whole document works for me:
def drawGUI():
...
cursor.mergeCharFormat(format_)
def clear():
cursor = editBox.textCursor()
cursor.select(QtGui.QTextCursor.Document)
cursor.setCharFormat(QtGui.QTextCharFormat())
cursor.clearSelection()
editBox.setTextCursor(cursor)
button = QtGui.QPushButton('Clear')
button.clicked.connect(clear)
layout = QtGui.QVBoxLayout(w)
layout.addWidget(editBox)
layout.addWidget(button)

Trasnparent Window in Maya 2017

i found a script by SAFRONOV 3D (on youtube) that allows him to make the graph editor transparent inside Maya... The problem is that it works on Maya 2014 and i'm Trying to update it to 2017.
I know very little of opne maya and all that, i´m a beginner in pymel and some help would be great. What's Wrong? :
import maya.cmds as cmds
import maya.OpenMayaUI as mui
import shiboken2
import maya.mel as mel
from PySide2 import QtGui
mel.eval('GraphEditor')
def getGraphEditor():
ptr2 = mui.MQtUtil.findLayout("graphEditor1Window|TearOffPane")
return shiboken2.wrapInstance(long(ptr2), QtGui.QWidget)
graphEditor = getGraphEditor()
graphEditor.setWindowOpacity(0.5)
def ref(value):
graphEditor.setWindowOpacity(value)
cmds.floatSlider(p="graphEditor1Window|TearOffPane|graphEditor", min = 0.1 , max = 1.0, v = 0.7, dc = lambda x:ref(x))
Here is my updated script:
import maya.cmds as cmds
import maya.OpenMayaUI as mui
from PySide2 import QtWidgets
import shiboken2
if cmds.window("GEW", exists=True): cmds.deleteUI("GEW", window=True)
cmds.window( "GEW", title="Graph Editor +" )
cmds.paneLayout( configuration='single' )
cmds.scriptedPanel( type='graphEditor' )
cmds.columnLayout (adj=1)
cmds.floatSlider(min=0.1, max=1.0, v=0.7, dc=lambda x:ref(x))
cmds.showWindow("GEW")
GEQ = shiboken2.wrapInstance(long(mui.MQtUtil.findWindow( "GEW" )), QtWidgets.QWidget)
def ref(value): GEQ.setWindowOpacity(value)
GEQ.setWindowOpacity(0.7)

The DateAxisItem sometimes becomes invisible

I checked out this version of pyqtgraph
git clone https://github.com/3rdcycle/pyqtgraph.git
git checkout origin/date-axis-item
pip uninstall pyqtgraph
python setup.py install
I then run this program. It appears to run fine, except that my x-axes of timestamps goes in and out of view without me doing anything. Not sure if this is a bug in this program or in DateAxisItem. Also, the milliseconds are always a multiple of 100. So for example, I see 00:00:00:900, 00:00:01:200, but never 00:00:00:042?
# -*- coding: utf-8 -*-
"""
Created on Thu May 14 21:09:44 2015
#author: idf
"""
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from PySide.QtCore import QTime, QTimer
from collections import deque
t = QTime()
t.start()
data = deque(maxlen=20)
class TimeAxisItem(pg.DateAxisItem):
def __init__(self, *args, **kwargs):
super(TimeAxisItem, self).__init__(*args, **kwargs)
def tickStrings(self, values, scale, spacing):
return [QTime().addMSecs(value).toString('hh:mm:ss.zzz') for value in values]
app = QtGui.QApplication([])
win = pg.GraphicsWindow(title="Basic time-plotting examples")
win.resize(1000,600)
plot = win.addPlot(title='Timed data', axisItems={'bottom': TimeAxisItem(orientation='bottom')})
curve = plot.plot()
def update():
global plot, curve, data
data.append({'x': t.elapsed(), 'y': np.random.randint(0, 100)})
x = [item['x'] for item in data]
y = [item['y'] for item in data]
curve.setData(x=x, y=y)
tmr = QTimer()
tmr.timeout.connect(update)
tmr.start(800)
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
I'm not sure what happens with your DateAxisItem. As you know it's not yet merged into the main development branch of PyQtGraph. However, for your particular application, it might be easier to start from scratch and define your own TimeAxisItem? If you start from the following code, what functionality would be missing?
class TimeAxisItem(AxisItem):
def __init__(self, orientation, **kwargs):
super().__init__(orientation, **kwargs)
def tickStrings(self, values, scale, spacing):
return [self.get_tick(v, spacing) for v in values]
def get_tick(self, ts, spacing):
dt = datetime.datetime.fromtimestamp(ts)
# Here you can decide on the accuracy of the time data
# displayed depending on the spacing.
if spacing > 60:
return "%02d:%02d" % (dt.hour, dt.minute)
else:
return "%02d:%02d:%02d" % (dt.hour, dt.minute, dt.second)

How can I implement global hot key in Python .app on Mac OS X?

I'm currently modifying an app that was written by someone within my organization that no longer is able to maintain it. I am attempting to implement a system-wide global hot key that will simply bring the app window into focus when pressed.
The only implementation of this I came across online was through PyObjC in their HotKeyPython example. That example uses Carbon though, and did not appear to function at all when I was testing it.
Here's what I was trying which did not appear to work:
from Foundation import *
from AppKit import *
from Carbon.CarbonEvt import RegisterEventHotKey
from Carbon.Events import cmdKey, controlKey, optionKey, shiftKey
import objc, AppLauncher
import platform
import struct
IS_SNOW_LEOPARD = platform.mac_ver()[0].startswith('10.6')
if IS_SNOW_LEOPARD:
from Quartz import *
kEventHotKeyPressedSubtype = 6
kEventHotKeyReleasedSubtype = 9
class AppLauncher(NSObject):
window = objc.IBOutlet()
view = objc.IBOutlet()
field = objc.IBOutlet()
def awakeFromNib(self):
self.window.makeFirstResponder_(self.field)
self.field.selectText_(self)
self.field.setDelegate_(self)
self.controlTextDidChange_(None)
def applicationDidFinishLaunching(self):
# register cmd-control-J
self.hotKeyRef = RegisterEventHotKey(38, cmdKey + controlKey, (0, 0),
sendEvent_(), 0)
def sendEvent_(self, theEvent):
if theEvent.type() == NSSystemDefined and \
theEvent.subtype() == kEventHotKeyPressedSubtype:
self.activateIgnoringOtherApps_(True)
NSRunAlertPanel(u'Hot Key Pressed', u'Hot Key Pressed',
None, None, None)
super(AppLauncher, self).sendEvent_(theEvent)
Any thoughts on how I can get this working (preferably without getting Carbon involved)?
Thanks a lot.

Categories

Resources