在 GUI 中堆叠两个小部件 [英] Stack two widgets in a GUI
问题描述
来自
我想在此配置中添加另一个小部件:
我试图使用 QGridLayout()
来解决问题的简化版本(下面是 MWE).
我尝试过的(MWE 下面).我得到了这样的东西(图都被压扁了一侧):
改变网格坐标没有任何影响.
MWE:
导入 PyQt5从 PyQt5 导入 QtGui、QtCore将 pyqtgraph 导入为 pg导入系统将 numpy 导入为 np宽度 = 1000高度 = 500类布局():定义设置(自我,窗口):self.window = 窗口self.window.resize(宽度,高度)grid = PyQt5.QtWidgets.QGridLayout()self.dialogue = QtGui.QTextEdit()grid.addWidget(self.dialogue, 100, 0)self.plot = pg.GraphicsLayoutWidget(self.window)grid.addWidget(self.plot, 200, 200)类窗口(pg.Qt.QtGui.QMainWindow,布局):def __init__(self, shot = None):super(Window, self).__init__()self.setup(self)自我展示()如果 __name__ == '__main__':app = pg.Qt.QtGui.QApplication([])窗户()sys.exit(app.exec_())
OP提供的代码中的错误是:
从未在小部件中设置布局 (QGridLayout).Qt 布局不是视觉元素,而是小部件几何形状的管理器.
如果使用 QMainWindow,则必须设置一个 centralWidget.
导入系统将 pyqtgraph 导入为 pg从 pyqtgraph.Qt 导入 QtGui、QtCore宽度 = 1000高度 = 500班级布置:定义设置(自我,窗口):self.window = 窗口self.window.resize(宽度,高度)网格 = QtGui.QGridLayout()self.dialogue = QtGui.QTextEdit()grid.addWidget(self.dialogue, 100, 0)self.plot = pg.GraphicsLayoutWidget()grid.addWidget(self.plot, 200, 200)central_widget = QtGui.QWidget()window.setCentralWidget(central_widget)central_widget.setLayout(网格)类窗口(pg.Qt.QtGui.QMainWindow,布局):def __init__(self, shot=None):super(Window, self).__init__()self.setup(self)如果 __name__ == __main__":app = QtGui.QApplication([])w = 窗口()w.show()sys.exit(app.exec_())
无论如何,那个问题与最初的问题无关.
可能(因为 OP 没有提供对初始目标的任何尝试)错误是认为添加相同的小部件 2 次会创建 2 个副本,但事实并非如此,当您将小部件添加到布局时它将从以前的位置移除.解决方案是创建 2 个小部件.为此,最好创建一个允许以简单方式实现此逻辑的类.
导入系统将 pyqtgraph 导入为 pg从 pyqtgraph.Qt 导入 QtCore、QtGui将 numpy 导入为 np从 glumpy 导入应用程序为 glumpy_app、gl、gloo、数据、库从 glumpy.geometry 导入基元from glumpy.transforms 导入轨迹球宽度 = 1000高度 = 500glumpy_app.use("qt5")顶点=""#include "misc/spatial-filters.frag";统一的浮动高度;统一采样器2D数据;统一 vec2 data_shape;属性 vec3 位置;属性 vec2 texcoord;改变 vec3 v_position;不同的 vec2 v_texcoord;无效主(){float z = height*Bicubic(data, data_shape, texcoord).r;gl_Position = <变换>;v_texcoord = texcoord;v_position = vec3(position.xy, z);}"片段=""#include "misc/spatial-filters.frag";统一的 mat4 模型;统一 mat4 视图;均匀 mat4 正常;统一的 sampler2D 纹理;统一的浮动高度;统一的 vec4 颜色;统一采样器2D数据;统一 vec2 data_shape;统一 vec3 light_color[3];统一 vec3 light_position[3];改变 vec3 v_position;不同的 vec2 v_texcoord;浮动照明(vec3 v_normal,vec3 light_position){//计算世界坐标中的法线vec3 n = normalize(normal * vec4(v_normal,1.0)).xyz;//计算这个片段(像素)在世界坐标中的位置vec3 位置 = vec3(视图 * 模型 * vec4(v_position, 1));//计算从这个像素表面到光源的向量vec3 surface_to_light = light_position - 位置;//计算入射角的余弦(亮度)浮动亮度 = 点(n,surface_to_light)/(长度(surface_to_light) * 长度(n));亮度 = max(min(brightness,1.0),0.0);返回亮度;}无效主(){mat4 模型 = <transform.trackball_model>;//提取数据值浮点值 = Bicubic(data, data_shape, v_texcoord).r;//使用邻居值计算表面法线float hx0 = height*Bicubic(data, data_shape, v_texcoord+vec2(+1,0)/data_shape).r;float hx1 = height*Bicubic(data, data_shape, v_texcoord+vec2(-1,0)/data_shape).r;float hy0 = height*Bicubic(data, data_shape, v_texcoord+vec2(0,+1)/data_shape).r;float hy1 = height*Bicubic(data, data_shape, v_texcoord+vec2(0,-1)/data_shape).r;vec3 dx = vec3(2.0/data_shape.x,0.0,hx0-hx1);vec3 dy = vec3(0.0,2.0/data_shape.y,hy0-hy1);vec3 v_normal = normalize(cross(dx,dy));//将值映射到 rgb 颜色浮动 c = 0.6 + 0.4*texture2D(texture, v_texcoord).r;vec4 l1 = vec4(light_color[0] * 照明(v_normal, light_position[0]), 1);vec4 l2 = vec4(light_color[1] * 灯光(v_normal, light_position[1]), 1);vec4 l3 = vec4(light_color[2] * 灯光(v_normal, light_position[2]), 1);gl_FragColor = 颜色 * vec4(c,c,c,1) * (0.5 + 0.5*(l1+l2+l3));} """def func3(x, y):返回 (1 - x/2 + x ** 5 + y ** 3) * np.exp(-(x ** 2) - y ** 2)类查看器(QtGui.QWidget):def __init__(self, parent=None):super().__init__(parent)self.glumpy_window = glumpy_app.Window(颜色=(1, 1, 1, 1))躺 = QtGui.QVBoxLayout(self)Lay.addWidget(self.glumpy_window._native_window)n = 64self.surface = gloo.Program(顶点,片段)self.vertices, self.s_indices =primitives.plane(2.0, n=n)self.surface.bind(self.vertices)我 = []对于范围(n)中的我:I.append(i)对于范围内的 i (1, n):I.append(n - 1 + i * n)对于范围内的 i (n - 1):I.append(n * n - 1 - i)对于范围内的 i (n - 1):I.append(n * (n - 1) - i * n)self.b_indices = np.array(I, dtype=np.uint32).view(gloo.IndexBuffer)x = np.linspace(-2.0, 2.0, 32).astype(np.float32)y = np.linspace(-2.0, 2.0, 32).astype(np.float32)X, Y = np.meshgrid(x, y)Z = func3(X, Y)self.surface[data"] = (Z - Z.min())/(Z.max() - Z.min())self.surface[data"].interpolation = gl.GL_NEARESTself.surface[data_shape"] = Z.shape[1], Z.shape[0]self.surface[u_kernel"] = data.get(spatial-filters.npy")self.surface[u_kernel"].interpolation = gl.GL_LINEARself.surface[texture"] = data.checkerboard(32, 24)self.transform = Trackball("vec4(position.xy, z, 1.0)")self.surface[transform"] = self.transformself.glumpy_window.attach(self.transform)T = (Z - Z.min())/(Z.max() - Z.min())self.surface[高度"] = 0.75self.surface[light_position[0]"] = 3, 0, 0 + 5self.surface[light_position[1]"] = 0, 3, 0 + 5self.surface[light_position[2]"] = -3, -3, +5self.surface[light_color[0]"] = 1, 0, 0self.surface[light_color[1]"] = 0, 1, 0self.surface[light_color[2]"] = 0, 0, 1p theta = -45, 0self.time = 0self.glumpy_window.set_handler("on_init", self.on_init)self.glumpy_window.set_handler("on_draw", self.on_draw)def on_init(self):gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)gl.glPolygonOffset(1, 1)gl.glEnable(gl.GL_LINE_SMOOTH)gl.glLineWidth(2.5)def on_draw(self, dt):self.time += dtself.glumpy_window.clear()self.surface[数据"]gl.glDisable(gl.GL_BLEND)gl.glEnable(gl.GL_DEPTH_TEST)gl.glEnable(gl.GL_POLYGON_OFFSET_FILL)self.surface[颜色"] = 1, 1, 1, 1self.surface.draw(gl.GL_TRIANGLES,self.s_indices)gl.glDisable(gl.GL_POLYGON_OFFSET_FILL)gl.glEnable(gl.GL_BLEND)gl.glDepthMask(gl.GL_FALSE)self.surface[颜色"] = 0, 0, 0, 1self.surface.draw(gl.GL_LINE_LOOP, self.b_indices)gl.glDepthMask(gl.GL_TRUE)model = self.surface[transform"][model"].reshape(4, 4)view = self.surface[transform"][view"].reshape(4, 4)self.surface[视图"] = 视图self.surface[模型"] = 模型self.surface[normal"] = np.array(np.matrix(np.dot(view, model)).I.T)self.surface[高度"] = 0.75 * np.cos(self.time)def showEvent(self, event):super().showEvent(事件)self.glumpy_window.dispatch_event("on_resize", *self.glumpy_window.get_size())班级布置:定义设置(自我,窗口):self.window = 窗口self.window.resize(宽度,高度)self.dialogue = QtGui.QTextEdit()self.plot = pg.GraphicsLayoutWidget(self.window)self.plot1 = self.plot.addPlot(colspan=1)self.centralwidget = QtGui.QWidget(self.window)self.horizontallayout = QtGui.QHBoxLayout(self.centralwidget)self.window.setCentralWidget(self.centralwidget)self.top_viewer = 查看器()self.bottom_viewer = Viewer()right_container = QtGui.QWidget()躺 = QtGui.QVBoxLayout(right_container)Lay.addWidget(self.top_viewer)Lay.addWidget(self.bottom_viewer)self.horizontallayout.addWidget(self.dialogue,stretch=1)self.horizontallayout.addWidget(self.plot,stretch=1)self.horizontallayout.addWidget(right_container,stretch=1)类窗口(QtGui.QMainWindow,布局):def __init__(self, shot=None):super(Window, self).__init__()self.setup(self)def closeEvent(self, event):super().closeEvent(事件)对于(self.top_viewer,self.bottom_viewer)中的查看器:viewer.glumpy_window.close()如果 __name__ == __main__":app = pg.Qt.QtGui.QApplication([])w = 窗口()w.show()glumpy_app.run()
From this answer I have code that adds a number of Widgets to a PyQt5 GUI:
I would like to add another widget just in this configuration:
I was trying to play around with QGridLayout()
, for a simplified version of the problem (MWE below).
What I tried (MWE below). I get something like this (plots all squashed on one side):
and varying the grid coordinates has no effect whatsoever.
MWE:
import PyQt5
from PyQt5 import QtGui, QtCore
import pyqtgraph as pg
import sys
import numpy as np
width = 1000
height = 500
class layout():
def setup(self, window):
self.window = window
self.window.resize(width, height)
grid = PyQt5.QtWidgets.QGridLayout()
self.dialogue = QtGui.QTextEdit()
grid.addWidget(self.dialogue , 100, 0)
self.plot = pg.GraphicsLayoutWidget(self.window)
grid.addWidget(self.plot , 200, 200)
class Window(pg.Qt.QtGui.QMainWindow, layout):
def __init__(self, shot = None):
super(Window, self).__init__()
self.setup(self)
self.show()
if __name__ == '__main__':
app = pg.Qt.QtGui.QApplication([])
Window()
sys.exit(app.exec_())
The errors in the code provided by the OP are:
The layout (QGridLayout) was never set in a widget. The Qt layouts are not visual elements but managers of the geometry of the widgets.
A centralWidget must be set if a QMainWindow is used.
import sys
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
width = 1000
height = 500
class layout:
def setup(self, window):
self.window = window
self.window.resize(width, height)
grid = QtGui.QGridLayout()
self.dialogue = QtGui.QTextEdit()
grid.addWidget(self.dialogue, 100, 0)
self.plot = pg.GraphicsLayoutWidget()
grid.addWidget(self.plot, 200, 200)
central_widget = QtGui.QWidget()
window.setCentralWidget(central_widget)
central_widget.setLayout(grid)
class Window(pg.Qt.QtGui.QMainWindow, layout):
def __init__(self, shot=None):
super(Window, self).__init__()
self.setup(self)
if __name__ == "__main__":
app = QtGui.QApplication([])
w = Window()
w.show()
sys.exit(app.exec_())
Anyway, that problem has nothing to do with the initial problem.
Probably (since the OP does not provide any attempt to the initial goal) the error is that it is thought that adding the same widget 2 times will create 2 copies but it is not, when you add a widget to a layout then it will be removed from its previous position. The solution is to create 2 widgets. For this, it is better to create a class that allows to implement this logic in a simple way.
import sys
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from glumpy import app as glumpy_app, gl, gloo, data, library
from glumpy.geometry import primitives
from glumpy.transforms import Trackball
width = 1000
height = 500
glumpy_app.use("qt5")
vertex = """
#include "misc/spatial-filters.frag"
uniform float height;
uniform sampler2D data;
uniform vec2 data_shape;
attribute vec3 position;
attribute vec2 texcoord;
varying vec3 v_position;
varying vec2 v_texcoord;
void main()
{
float z = height*Bicubic(data, data_shape, texcoord).r;
gl_Position = <transform>;
v_texcoord = texcoord;
v_position = vec3(position.xy, z);
}
"""
fragment = """
#include "misc/spatial-filters.frag"
uniform mat4 model;
uniform mat4 view;
uniform mat4 normal;
uniform sampler2D texture;
uniform float height;
uniform vec4 color;
uniform sampler2D data;
uniform vec2 data_shape;
uniform vec3 light_color[3];
uniform vec3 light_position[3];
varying vec3 v_position;
varying vec2 v_texcoord;
float lighting(vec3 v_normal, vec3 light_position)
{
// Calculate normal in world coordinates
vec3 n = normalize(normal * vec4(v_normal,1.0)).xyz;
// Calculate the location of this fragment (pixel) in world coordinates
vec3 position = vec3(view * model * vec4(v_position, 1));
// Calculate the vector from this pixels surface to the light source
vec3 surface_to_light = light_position - position;
// Calculate the cosine of the angle of incidence (brightness)
float brightness = dot(n, surface_to_light) /
(length(surface_to_light) * length(n));
brightness = max(min(brightness,1.0),0.0);
return brightness;
}
void main()
{
mat4 model = <transform.trackball_model>;
// Extract data value
float value = Bicubic(data, data_shape, v_texcoord).r;
// Compute surface normal using neighbour values
float hx0 = height*Bicubic(data, data_shape, v_texcoord+vec2(+1,0)/data_shape).r;
float hx1 = height*Bicubic(data, data_shape, v_texcoord+vec2(-1,0)/data_shape).r;
float hy0 = height*Bicubic(data, data_shape, v_texcoord+vec2(0,+1)/data_shape).r;
float hy1 = height*Bicubic(data, data_shape, v_texcoord+vec2(0,-1)/data_shape).r;
vec3 dx = vec3(2.0/data_shape.x,0.0,hx0-hx1);
vec3 dy = vec3(0.0,2.0/data_shape.y,hy0-hy1);
vec3 v_normal = normalize(cross(dx,dy));
// Map value to rgb color
float c = 0.6 + 0.4*texture2D(texture, v_texcoord).r;
vec4 l1 = vec4(light_color[0] * lighting(v_normal, light_position[0]), 1);
vec4 l2 = vec4(light_color[1] * lighting(v_normal, light_position[1]), 1);
vec4 l3 = vec4(light_color[2] * lighting(v_normal, light_position[2]), 1);
gl_FragColor = color * vec4(c,c,c,1) * (0.5 + 0.5*(l1+l2+l3));
} """
def func3(x, y):
return (1 - x / 2 + x ** 5 + y ** 3) * np.exp(-(x ** 2) - y ** 2)
class Viewer(QtGui.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.glumpy_window = glumpy_app.Window(color=(1, 1, 1, 1))
lay = QtGui.QVBoxLayout(self)
lay.addWidget(self.glumpy_window._native_window)
n = 64
self.surface = gloo.Program(vertex, fragment)
self.vertices, self.s_indices = primitives.plane(2.0, n=n)
self.surface.bind(self.vertices)
I = []
for i in range(n):
I.append(i)
for i in range(1, n):
I.append(n - 1 + i * n)
for i in range(n - 1):
I.append(n * n - 1 - i)
for i in range(n - 1):
I.append(n * (n - 1) - i * n)
self.b_indices = np.array(I, dtype=np.uint32).view(gloo.IndexBuffer)
x = np.linspace(-2.0, 2.0, 32).astype(np.float32)
y = np.linspace(-2.0, 2.0, 32).astype(np.float32)
X, Y = np.meshgrid(x, y)
Z = func3(X, Y)
self.surface["data"] = (Z - Z.min()) / (Z.max() - Z.min())
self.surface["data"].interpolation = gl.GL_NEAREST
self.surface["data_shape"] = Z.shape[1], Z.shape[0]
self.surface["u_kernel"] = data.get("spatial-filters.npy")
self.surface["u_kernel"].interpolation = gl.GL_LINEAR
self.surface["texture"] = data.checkerboard(32, 24)
self.transform = Trackball("vec4(position.xy, z, 1.0)")
self.surface["transform"] = self.transform
self.glumpy_window.attach(self.transform)
T = (Z - Z.min()) / (Z.max() - Z.min())
self.surface["height"] = 0.75
self.surface["light_position[0]"] = 3, 0, 0 + 5
self.surface["light_position[1]"] = 0, 3, 0 + 5
self.surface["light_position[2]"] = -3, -3, +5
self.surface["light_color[0]"] = 1, 0, 0
self.surface["light_color[1]"] = 0, 1, 0
self.surface["light_color[2]"] = 0, 0, 1
phi, theta = -45, 0
self.time = 0
self.glumpy_window.set_handler("on_init", self.on_init)
self.glumpy_window.set_handler("on_draw", self.on_draw)
def on_init(self):
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glPolygonOffset(1, 1)
gl.glEnable(gl.GL_LINE_SMOOTH)
gl.glLineWidth(2.5)
def on_draw(self, dt):
self.time += dt
self.glumpy_window.clear()
self.surface["data"]
gl.glDisable(gl.GL_BLEND)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glEnable(gl.GL_POLYGON_OFFSET_FILL)
self.surface["color"] = 1, 1, 1, 1
self.surface.draw(gl.GL_TRIANGLES, self.s_indices)
gl.glDisable(gl.GL_POLYGON_OFFSET_FILL)
gl.glEnable(gl.GL_BLEND)
gl.glDepthMask(gl.GL_FALSE)
self.surface["color"] = 0, 0, 0, 1
self.surface.draw(gl.GL_LINE_LOOP, self.b_indices)
gl.glDepthMask(gl.GL_TRUE)
model = self.surface["transform"]["model"].reshape(4, 4)
view = self.surface["transform"]["view"].reshape(4, 4)
self.surface["view"] = view
self.surface["model"] = model
self.surface["normal"] = np.array(np.matrix(np.dot(view, model)).I.T)
self.surface["height"] = 0.75 * np.cos(self.time)
def showEvent(self, event):
super().showEvent(event)
self.glumpy_window.dispatch_event("on_resize", *self.glumpy_window.get_size())
class layout:
def setup(self, window):
self.window = window
self.window.resize(width, height)
self.dialogue = QtGui.QTextEdit()
self.plot = pg.GraphicsLayoutWidget(self.window)
self.plot1 = self.plot.addPlot(colspan=1)
self.centralwidget = QtGui.QWidget(self.window)
self.horizontallayout = QtGui.QHBoxLayout(self.centralwidget)
self.window.setCentralWidget(self.centralwidget)
self.top_viewer = Viewer()
self.bottom_viewer = Viewer()
right_container = QtGui.QWidget()
lay = QtGui.QVBoxLayout(right_container)
lay.addWidget(self.top_viewer)
lay.addWidget(self.bottom_viewer)
self.horizontallayout.addWidget(self.dialogue, stretch=1)
self.horizontallayout.addWidget(self.plot, stretch=1)
self.horizontallayout.addWidget(right_container, stretch=1)
class Window(QtGui.QMainWindow, layout):
def __init__(self, shot=None):
super(Window, self).__init__()
self.setup(self)
def closeEvent(self, event):
super().closeEvent(event)
for viewer in (self.top_viewer, self.bottom_viewer):
viewer.glumpy_window.close()
if __name__ == "__main__":
app = pg.Qt.QtGui.QApplication([])
w = Window()
w.show()
glumpy_app.run()
这篇关于在 GUI 中堆叠两个小部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!