在 GUI 中堆叠两个小部件 [英] Stack two widgets in a GUI

查看:70
本文介绍了在 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.horizo​​ntallayout = 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.horizo​​ntallayout.addWidget(self.dialogue,stretch=1)self.horizo​​ntallayout.addWidget(self.plot,stretch=1)self.horizo​​ntallayout.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆