- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在开发一个相当复杂的 GUI 程序,该程序将与 MATLAB Compiler 一起部署。 (有充分的理由使用 MATLAB 来构建此 GUI,这不是这个问题的重点。我意识到 GUI 构建不是这种语言的强项。)
有很多方法可以在 GUI 中的函数之间共享数据,甚至可以在应用程序中的 GUI 之间传递数据:
setappdata/getappdata/_____appdata
- 将任意数据关联到句柄guidata
- 通常与 GUIDE 一起使用; “存储 [s] 或检索 [s] GUI 数据”到句柄结构UserData
属性应用 set/get
操作我的代码结构不是最漂亮的。现在我将引擎与前端分离(很好!),但 GUI 代码非常像意大利面条。这是一个“事件”的骨架,借用 Android 的说法:
function myGui
fig = figure(...);
% h is a struct that contains handles to all the ui objects to be instantiated. My convention is to have the first field be the uicontrol type I'm instantiating. See draw_gui nested function
h = struct([]);
draw_gui;
set_callbacks; % Basically a bunch of set(h.(...), 'Callback', @(src, event) callback) calls would occur here
%% DRAW FUNCTIONS
function draw_gui
h.Panel.Panel1 = uipanel(...
'Parent', fig, ...
...);
h.Panel.Panel2 = uipanel(...
'Parent', fig, ...
...);
draw_panel1;
draw_panel2;
function draw_panel1
h.Edit.Panel1.thing1 = uicontrol('Parent', h.Panel.Panel1, ...);
end
function draw_panel2
h.Edit.Panel2.thing1 = uicontrol('Parent', h.Panel.Panel2, ...);
end
end
%% CALLBACK FUNCTIONS
% Setting/getting application data is done by set/getappdata(fig, 'Foo').
end
我之前编写的代码没有任何嵌套,所以我最终在各处来回传递 h
(因为需要重绘、更新等)和 setappdata(fig )
来存储实际数据。无论如何,我一直将一个“事件”保存在一个文件中,而且我确信这将成为 future 维护的噩梦。回调与应用程序数据和图形句柄对象交互,我认为这是必要的,但这阻止了代码库的两个“部分”的完全隔离。
所以我在这里寻找一些组织/GUI 设计方面的帮助。即:
设置/获取
处理对象的属性)。set/getappdata
是否会降低性能?我不是专业的软件工程师,我只是知道足够危险,所以我确信这些对于经验丰富的 GUI 开发人员(使用任何语言)都是相当基本的问题。我几乎觉得 MATLAB 中缺少 GUI 设计标准(是否存在?)严重干扰了我完成该项目的能力。这是一个 MATLAB 项目,比我做过的任何项目都要庞大,而且我以前从来没有考虑过具有多个图形窗口等的复杂 UI。
最佳答案
作为@SamRoberts解释,Model–view–controller (MVC) 模式非常适合作为设计 GUI 的架构。我同意没有很多 MATLAB 示例可以展示这种设计...
下面是我编写的一个完整而简单的示例,用于在 MATLAB 中演示基于 MVC 的 GUI。
模型 表示一些信号 y(t) = sin(..t..)
的一维函数。它是一个句柄类对象,这样我们就可以传递数据而不会创建不必要的副本。它公开可观察的属性,允许其他组件监听更改通知。
View 将模型呈现为线条图形对象。该 View 还包含一个 slider 来控制其中一个信号属性,并监听模型更改通知。我还包含了一个特定于 View (而非模型)的交互式属性,其中可以使用右键单击上下文菜单控制线条颜色。
Controller 负责初始化所有内容并响应来自 View 的事件,并相应地正确更新模型。
请注意, View 和 Controller 是作为常规函数编写的,但如果您更喜欢完全面向对象的代码,则可以编写类。
与通常的 GUI 设计方式相比,这需要一些额外的工作,但这种架构的优点之一是数据与表示层的分离。这使得代码更清晰、更易读,尤其是在使用复杂的 GUI 时,代码维护变得更加困难。
这种设计非常灵活,因为它允许您为同一数据构建多个 View 。您甚至可以拥有多个同时 View ,只需在 Controller 中实例化更多 View 实例,然后查看一个 View 中的更改如何传播到另一个 View !如果您的模型可以以不同的方式直观地呈现,这将特别有趣。
此外,如果您愿意,可以使用 GUIDE 编辑器构建界面,而不是以编程方式添加控件。在这样的设计中,我们只会使用 GUIDE 通过拖放来构建 GUI 组件,但不会编写任何回调函数。所以我们只对生成的 .fig
文件感兴趣,而忽略伴随的 .m
文件。我们将在 View 函数/类中设置回调。这基本上就是我在 View_FrequencyDomain
View 组件中所做的,它加载了使用 GUIDE 构建的现有 FIG 文件。
classdef Model < handle
%MODEL represents a signal composed of two components + white noise
% with sampling frequency FS defined over t=[0,1] as:
% y(t) = a * sin(2pi * f*t) + sin(2pi * 2*f*t) + white_noise
% observable properties, listeners are notified on change
properties (SetObservable = true)
f % frequency components in Hz
a % amplitude
end
% read-only properties
properties (SetAccess = private)
fs % sampling frequency (Hz)
t % time vector (seconds)
noise % noise component
end
% computable dependent property
properties (Dependent = true, SetAccess = private)
data % signal values
end
methods
function obj = Model(fs, f, a)
% constructor
if nargin < 3, a = 1.2; end
if nargin < 2, f = 5; end
if nargin < 1, fs = 100; end
obj.fs = fs;
obj.f = f;
obj.a = a;
% 1 time unit with 'fs' samples
obj.t = 0 : 1/obj.fs : 1-(1/obj.fs);
obj.noise = 0.2 * obj.a * rand(size(obj.t));
end
function y = get.data(obj)
% signal data
y = obj.a * sin(2*pi * obj.f*obj.t) + ...
sin(2*pi * 2*obj.f*obj.t) + obj.noise;
end
end
% business logic
methods
function [mx,freq] = computePowerSpectrum(obj)
num = numel(obj.t);
nfft = 2^(nextpow2(num));
% frequencies vector (symmetric one-sided)
numUniquePts = ceil((nfft+1)/2);
freq = (0:numUniquePts-1)*obj.fs/nfft;
% compute FFT
fftx = fft(obj.data, nfft);
% calculate magnitude
mx = abs(fftx(1:numUniquePts)).^2 / num;
if rem(nfft, 2)
mx(2:end) = mx(2:end)*2;
else
mx(2:end -1) = mx(2:end -1)*2;
end
end
end
end
function handles = View_TimeDomain(m)
%VIEW a GUI representation of the signal model
% build the GUI
handles = initGUI();
onChangedF(handles, m); % populate with initial values
% observe on model changes and update view accordingly
% (tie listener to model object lifecycle)
addlistener(m, 'f', 'PostSet', ...
@(o,e) onChangedF(handles,e.AffectedObject));
end
function handles = initGUI()
% initialize GUI controls
hFig = figure('Menubar','none');
hAx = axes('Parent',hFig, 'XLim',[0 1], 'YLim',[-2.5 2.5]);
hSlid = uicontrol('Parent',hFig, 'Style','slider', ...
'Min',1, 'Max',10, 'Value',5, 'Position',[20 20 200 20]);
hLine = line('XData',NaN, 'YData',NaN, 'Parent',hAx, ...
'Color','r', 'LineWidth',2);
% define a color property specific to the view
hMenu = uicontextmenu;
hMenuItem = zeros(3,1);
hMenuItem(1) = uimenu(hMenu, 'Label','r', 'Checked','on');
hMenuItem(2) = uimenu(hMenu, 'Label','g');
hMenuItem(3) = uimenu(hMenu, 'Label','b');
set(hLine, 'uicontextmenu',hMenu);
% customize
xlabel(hAx, 'Time (sec)')
ylabel(hAx, 'Amplitude')
title(hAx, 'Signal in time-domain')
% return a structure of GUI handles
handles = struct('fig',hFig, 'ax',hAx, 'line',hLine, ...
'slider',hSlid, 'menu',hMenuItem);
end
function onChangedF(handles,model)
% respond to model changes by updating view
if ~ishghandle(handles.fig), return, end
set(handles.line, 'XData',model.t, 'YData',model.data)
set(handles.slider, 'Value',model.f);
end
function handles = View_FrequencyDomain(m)
handles = initGUI();
onChangedF(handles, m);
hl = event.proplistener(m, findprop(m,'f'), 'PostSet', ...
@(o,e) onChangedF(handles,e.AffectedObject));
setappdata(handles.fig, 'proplistener',hl);
end
function handles = initGUI()
% load FIG file (its really a MAT-file)
hFig = hgload('ViewGUIDE.fig');
%S = load('ViewGUIDE.fig', '-mat');
% extract handles to GUI components
hAx = findobj(hFig, 'tag','axes1');
hSlid = findobj(hFig, 'tag','slider1');
hTxt = findobj(hFig, 'tag','fLabel');
hMenu = findobj(hFig, 'tag','cmenu1');
hMenuItem = findobj(hFig, 'type','uimenu');
% initialize line and hook up context menu
hLine = line('XData',NaN, 'YData',NaN, 'Parent',hAx, ...
'Color','r', 'LineWidth',2);
set(hLine, 'uicontextmenu',hMenu);
% customize
xlabel(hAx, 'Frequency (Hz)')
ylabel(hAx, 'Power')
title(hAx, 'Power spectrum in frequency-domain')
% return a structure of GUI handles
handles = struct('fig',hFig, 'ax',hAx, 'line',hLine, ...
'slider',hSlid, 'menu',hMenuItem, 'txt',hTxt);
end
function onChangedF(handles,model)
[mx,freq] = model.computePowerSpectrum();
set(handles.line, 'XData',freq, 'YData',mx)
set(handles.slider, 'Value',model.f)
set(handles.txt, 'String',sprintf('%.1f Hz',model.f))
end
function [m,v1,v2] = Controller
%CONTROLLER main program
% controller knows about model and view
m = Model(100); % model is independent
v1 = View_TimeDomain(m); % view has a reference of model
% we can have multiple simultaneous views of the same data
v2 = View_FrequencyDomain(m);
% hook up and respond to views events
set(v1.slider, 'Callback',{@onSlide,m})
set(v2.slider, 'Callback',{@onSlide,m})
set(v1.menu, 'Callback',{@onChangeColor,v1})
set(v2.menu, 'Callback',{@onChangeColor,v2})
% simulate some change
pause(3)
m.f = 10;
end
function onSlide(o,~,model)
% update model (which in turn trigger event that updates view)
model.f = get(o,'Value');
end
function onChangeColor(o,~,handles)
% update view
clr = get(o,'Label');
set(handles.line, 'Color',clr)
set(handles.menu, 'Checked','off')
set(o, 'Checked','on')
end
在上面的 Controller 中,我实例化了两个独立但同步的 View ,它们都表示和响应同一基础模型中的变化。一个 View 显示信号的时域,另一个 View 显示使用 FFT 的频域表示。
关于matlab - "right"GUI代码的组织方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20064610/
我是 Django 新手并开始了一个项目,我想以正确的方式去做。 我想知道您认为组织项目的最佳实践是什么。 以下是我的一些问题: 如何将静态资源与 Python 代码分开,以免浪费时间通过 Djang
通过这个组织,是否可以引用“id”属性? function house(id) { this.id = id } house.prototype.buy = function() { }
我的任务是“识别并修复任何错误”。这张取自 Java 教科书的图片显示了 Swing 结构的组织。这对我来说很好,我没有发现任何问题。 谁能解释一下? JPanel 应该放在 JComponent 之
重要的事情 是否可以确定 WHERE 条件的最佳顺序以使其更快?例如,我有一个包含 6 个条件的查询。一些简单,另一些带有子查询或函数。我的想法是对查询进行概要分析,以确定条件语句 true 的常见程
我有 Java/AS3/Javascript 背景,我的所有类都组织成包,以帮助表示它们的功能。 在开始一个 C++ 项目时,我试图以几乎相同的方式模仿这个文件系统结构,但我一直遇到包含问题。 目前我
我正在使用 CKAN 作为开放数据门户。我已经完成了 CKAN 实例的设置并添加了数据集、组和组织。 主页上有一个特色组和一个特色组织框。如何在主页上显示我想要的组和组织。 如何在主页上更改这些特色组
我已经创建了我的第一个 iPhone 应用程序,它可以在表格 View 中显示类似类型的音轨。用户可以使用类似 ipod 的控件来播放音轨,这些控件可以流式传输 mp3。 我的所有代码都在两个主要类中
我将我的代码组织成 20-60 行模块,通常采用模块模式。我想要一个结构良好的面向对象的 JavaScript 库。 这是最好的方法吗?代码已经过测试并且有效。 我喜欢它,因为程序员可以从库中提取模块
我正在使用 riot.js 和 jquery 构建一个应用程序。一切都按预期工作,但是随着代码的增长,我也担心在代码中随机/意外的地方触发和处理事件 (.trigger/.on) 对保持我的代码有条理
这是另一个 GIT 新手。 我想在我们的项目中使用 GIT。 团队不熟悉 GIT。 这些项目基本上由一些通用项目(*)和一些应用项目组成。应用程序正在使用公地,公地也可以使用其他公地。通过“使用”我的
例如,考虑一个组织有一个包含两个分支的存储库的情况,master 和 1.0.0.1。 是否可以让团队对 master 具有只读访问权限,而对分支 (1.0.0.1) 具有读写访问权限? 最佳答案 自
我一直致力于寻找组织 CSS 代码的最佳方式,尤其是在大型网站上。我对编写风格不太感兴趣,而对人们如何构建和管理他们的代码更感兴趣。 我一直在遵循这个结构,我觉得它在可维护性方面工作得很好,但我想听取
我们正在扩展到一个大型微服务构建,并通过 postman 完成更多测试(现场验证、错误测试等)。好奇...您的团队如何组织大量 API 的集合? (按 API、按测试类型、按发布等)从一个团队传递到另
我最近遇到了这个编码面试问题,但似乎找不到答案。这是问题。 给定一个整数数组,编写一个函数,返回组织数组所需的最小交换,使得相邻元素的绝对差都小于或等于 K。交换可以是任意两个数组元素,不一定是相邻的
我有 100 多页。所有页面都使用不同的模板。 目前,我有一长串 .state('page.html').state('page2.html') 等。10-15 页后,我认为这变得不可读/难以管理。
我看下grails-app/i18n有一吨messages*.properties捆绑。我想将我的应用程序国际化,但每页有 1 个“捆绑集”。我所说的包集是指包含相同文本但用于不同语言的一组包/属性文
我正在编写一个非常非常长的 CUDA 内核,它对人类的可读性来说非常糟糕。有什么方法可以用内核外部的功能组织 CUDA 内核吗?示例: __global__ void CUDA_Kernel(int*
我的公司要求我将Outlook用于我的电子邮件。 Outlook几乎不执行我想做的任何事情,这让我感到非常沮丧。 (我并不是要在这里发动一场火焰大战,它必须完全执行数千名CEO想要做的事情,但我不是C
我一直在尝试一些不同的方法来组织我的 javascript 应用程序中的代码,我想知道哪种方法最合适。 第一个例子: var Application = { init: function()
Angular 样式指南包含有关在应用程序中使用类和接口(interface)的最佳实践的信息。但它没有任何关于如何组织我的接口(interface)和模型类的信息。 有一个问题:关于文件和类的组织有
我是一名优秀的程序员,十分优秀!