我正在嘗試使用 PyQt5 來顯示兩個小部件,第一個是 sin、cos 和 tan 函式的圖。我正在使用pyqtgraph并使用在這個問題的答案中找到的代碼。我還使用另一個使用 PyOpenGL 繪制立方體的小部件,以在此鏈接中找到的示例為例。我試圖在一個主視窗小部件中顯示這兩個小部件。我的方法如下
- 拿一個主要的小部件。
- 在主小部件中,使用 QVBoxLayout()
- 在 QVBoxLayout 中,在上面提到的兩個小部件處
但是當我運行代碼時,只pyqtgraph顯示使用 的圖,而不顯示使用 繪制的立方體PyOpenGL。經過一些除錯后,我發現立方體小部件的高度默認設定為 0。我不確定為什么會這樣。我試著打電話glWidget.resize(640,480)。但它沒有用。我是 PyQt 和 PyOpenGL 的新手。glWidget如果我的假設是正確的,我想我會遺漏一些細節,這些細節將使高度大于 0。我也不確定這是否真的可以做到。我目前的代碼如下,有點亂。
import sys
from OpenGL.GL.images import asWrapper
from PyQt5.QtWidgets import QApplication, QGridLayout
from PyQt5 import QtWidgets
import pyqtgraph as pg
from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt5 import QtGui
from PyQt5.QtOpenGL import *
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np
from PyQt5 import QtOpenGL
import OpenGL.GL as gl
from OpenGL import GLU
from OpenGL.arrays import vbo
class TimeLine(QtCore.QObject):
frameChanged = QtCore.pyqtSignal(int)
def __init__(self, interval=60, loopCount=1, parent=None):
super(TimeLine, self).__init__(parent)
self._startFrame = 0
self._endFrame = 0
self._loopCount = loopCount
self._timer = QtCore.QTimer(self, timeout=self.on_timeout)
self._counter = 0
self._loop_counter = 0
self.setInterval(interval)
def on_timeout(self):
if self._startFrame <= self._counter < self._endFrame:
self.frameChanged.emit(self._counter)
self._counter = 1
else:
self._counter = 0
self._loop_counter = 1
if self._loopCount > 0:
if self._loop_counter >= self.loopCount():
self._timer.stop()
def setLoopCount(self, loopCount):
self._loopCount = loopCount
def loopCount(self):
return self._loopCounts
interval = QtCore.pyqtProperty(int, fget=loopCount, fset=setLoopCount)
def setInterval(self, interval):
self._timer.setInterval(interval)
def interval(self):
return self._timer.interval()
interval = QtCore.pyqtProperty(int, fget=interval, fset=setInterval)
def setFrameRange(self, startFrame, endFrame):
self._startFrame = startFrame
self._endFrame = endFrame
@QtCore.pyqtSlot()
def start(self):
self._counter = 0
self._loop_counter = 0
self._timer.start()
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent = None):
self.parent = parent
QtOpenGL.QGLWidget.__init__(self, parent)
self.resizeGL(640,800)
def initializeGL(self):
self.qglClearColor(QtGui.QColor(0,0,255))
gl.glEnable(gl.GL_DEPTH_TEST)
self.initGeometry()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
def resizeGL(self, width, height):
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
print(width, height)
aspect = width / float(height)
GLU.gluPerspective(45.0, aspect, 1.0, 100.0)
gl.glMatrixMode(gl.GL_MODELVIEW)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glPushMatrix()
gl.glTranslate(0.0, 0.0, -50.0)
gl.glScale(20.0, 20.0, 20.0)
gl.glRotate(self.rotX, 1.0, 0.0, 0.0)
gl.glRotate(self.rotY, 0.0, 1.0, 0.0)
gl.glRotate(self.rotZ, 0.0, 0.0, 1.0)
gl.glTranslate(-0.5, -0.5, -0.5)
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
gl.glEnableClientState(gl.GL_COLOR_ARRAY)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, self.vertVBO)
gl.glColorPointer(3, gl.GL_FLOAT, 0, self.colorVBO)
gl.glDrawElements(gl.GL_QUADS, len(self.cubeIdxArray), gl.GL_UNSIGNED_INT, self.cubeIdxArray)
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
gl.glDisableClientState(gl.GL_COLOR_ARRAY)
gl.glPopMatrix()
def initGeometry(self):
self.cubeVtxArray = np.array(
[[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0]])
self.vertVBO = vbo.VBO(np.reshape(self.cubeVtxArray,
(1, -1)).astype(np.float32))
self.vertVBO.bind()
self.cubeClrArray = np.array(
[[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0 ]])
self.colorVBO = vbo.VBO(np.reshape(self.cubeClrArray,
(1, -1)).astype(np.float32))
self.colorVBO.bind()
self.cubeIdxArray = np.array(
[0, 1, 2, 3,
3, 2, 6, 7,
1, 0, 4, 5,
2, 1, 5, 6,
0, 3, 7, 4,
7, 6, 5, 4 ])
def setRotX(self, val):
self.rotX = np.pi * val
def setRotY(self, val):
self.rotY = np.pi * val
def setRotZ(self, val):
self.rotZ = np.pi * val
class MainGui(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.resize(600,600)
self.cube = GLWidget(self)
self.setupUI()
def setupUI(self):
central_widget = QtWidgets.QWidget()
central_layout = QtWidgets.QVBoxLayout()
central_widget.setLayout(central_layout)
self.setCentralWidget(central_widget)
pg.setConfigOption('background',0.95)
pg.setConfigOptions(antialias=True)
self.plot = pg.PlotWidget()
self.plot.setAspectLocked(lock = True, ratio = 0.01)
#self.cube = GLWidget(self)
#self.cube.resize(200,200)
central_layout.addWidget(self.cube)
central_layout.addWidget(self.plot)
self._plots = [self.plot.plot([], [], pen=pg.mkPen(color=color, width=2)) for color in ('g', 'r', 'y')]
self._timeline = TimeLine(loopCount = 0, interval = 10)
self._timeline.setFrameRange(0,720)
self._timeline.frameChanged.connect(self.generate_data)
self._timeline.start()
def plot_data(self, data):
for plt, val in zip(self._plots, data):
plt.setData(range(len(val)),val)
@QtCore.pyqtSlot(int)
def generate_data(self, i):
ang = np.arange(i, i 720)
cos_func = np.cos(np.radians(ang))
sin_func = np.sin(np.radians(ang))
tan_func = sin_func/cos_func
tan_func[(tan_func < -3) | (tan_func > 3)] = np.NaN
self.plot_data([sin_func, cos_func, tan_func])
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
gui = MainGui()
gui.show()
sys.exit(app.exec_())
uj5u.com熱心網友回復:
似乎 QGLWidget(順便說一句,已棄用,應改用QOpenGLWidget)未實作sizeHint(),因此它回傳無效大小 ( QSize(-1, -1)),這意味著小部件可能會調整為 0 寬度和/或高度。
由于繪圖小部件具有擴展尺寸策略(并動態重新實作sizeHint()),因此結果是 gl 小部件完全隱藏,高度為 0。
一個可能的解決方案是將帶有適當stretch引數的小部件添加到布局中。
如果您希望兩個小部件具有相同的高度,您可以執行以下操作:
central_layout.addWidget(self.cube, stretch=1)
central_layout.addWidget(self.plot, stretch=1)
請注意,拉伸是基于比率的(僅考慮整數),因此,如果您希望立方體具有圖的一半高度:
central_layout.addWidget(self.cube, stretch=1)
central_layout.addWidget(self.plot, stretch=2)
或者,您可以使用setMinimumHeight()gl 小部件,但由于繪圖具有擴展策略(通常優先),因此該 gl 小部件將始終具有該高度。更好的解決方案是為 gl 小部件和實施設定擴展策略QSizeHint,但請記住,繪圖小部件具有動態大小提示,因此它始終需要一定量的“大小優先級”。
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent = None):
QtOpenGL.QGLWidget.__init__(self, parent)
self.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
def sizeHint(self):
return QtCore.QSize(300, 150)
# ...
應該沒有必要手動呼叫resizeGL()的__init__,你也應該總是使用動態訪問parent()函式來獲取父。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/383969.html
下一篇:Unity如何通過腳本創建文本?
