我需要在 Matlab 中创建一个 GUI,使我能够交互式地绘制图形,并为边和顶点赋值。
然后,我需要为边返回这些值 (x, y, value),为顶点返回 (x1, y1, x2, y2, value)。
不幸的是,我什至不知道从哪里开始。我创建了一个 gui,让我可以使用 2 种不同的方法交互式地画线,但我不知道如何继续。请帮忙。
我需要在 Matlab 中创建一个 GUI,使我能够交互式地绘制图形,并为边和顶点赋值。
然后,我需要为边返回这些值 (x, y, value),为顶点返回 (x1, y1, x2, y2, value)。
不幸的是,我什至不知道从哪里开始。我创建了一个 gui,让我可以使用 2 种不同的方法交互式地画线,但我不知道如何继续。请帮忙。
您始终可以处理鼠标事件以启用交互式绘图。我花了一些时间在这上面,并提出了以下 GUI。
function interactive_graph_gui
% data
showLabels = false; % flag to determine whether to show node labels
prevIdx = []; % keeps track of 1st node clicked in creating edges
selectIdx = []; % used to highlight node selected in listbox
pts = zeros(0,2); % x/y coordinates of vertices
adj = sparse([]); % sparse adjacency matrix (undirected)
% create GUI
h = initGUI();
function h = initGUI()
h.fig = figure('Name','Interactive Graph', 'Resize','off');
h.ax = axes('Parent',h.fig, 'ButtonDownFcn',@onMouseDown, ...
'XLim',[0 1], 'YLim',[0 1], 'XTick',[], 'YTick',[], 'Box','on', ...
'Units','pixels', 'Position',[160 20 380 380]);
h.list = uicontrol('Style','listbox', 'Parent',h.fig, 'String',{}, ...
'Min',1, 'Max',1, 'Value',1, ...
'Position',[20 80 130 320], 'Callback',@onSelect);
uicontrol('Style','pushbutton', 'Parent',h.fig, 'String','Clear', ...
'Position',[20 20 60 20], 'Callback',@onClear);
uicontrol('Style','pushbutton', 'Parent',h.fig, 'String','Export', ...
'Position',[90 20 60 20], 'Callback',@onExport);
uicontrol('Style','pushbutton', 'Parent',h.fig, 'String','Delete', ...
'Position',[50 50 60 20], 'Callback',@onDelete);
h.cmenu = uicontextmenu('Parent',h.fig);
h.menu = uimenu(h.cmenu, 'Label','Show labels', 'Checked','off', ...
'Callback',@onCMenu);
set(h.list, 'UIContextMenu',h.cmenu)
h.pts = line(NaN, NaN, 'Parent',h.ax, 'HitTest','off', ...
'Marker','o', 'MarkerSize',10, 'MarkerFaceColor','b', ...
'LineStyle','none');
h.selected = line(NaN, NaN, 'Parent',h.ax, 'HitTest','off', ...
'Marker','o', 'MarkerSize',10, 'MarkerFaceColor','y', ...
'LineStyle','none');
h.prev = line(NaN, NaN, 'Parent',h.ax, 'HitTest','off', ...
'Marker','o', 'MarkerSize',20, 'Color','r', ...
'LineStyle','none', 'LineWidth',2);
h.edges = line(NaN, NaN, 'Parent',h.ax, 'HitTest','off', ...
'LineWidth',2, 'Color','g');
h.txt = [];
end
function onMouseDown(~,~)
% get location of mouse click (in data coordinates)
p = get(h.ax, 'CurrentPoint');
% determine whether normal left click was used or otherwise
if strcmpi(get(h.fig,'SelectionType'), 'Normal')
% add a new node
pts(end+1,:) = p(1,1:2);
adj(end+1,end+1) = 0;
else
% add a new edge (requires at least 2 nodes)
if size(pts,1) < 2, return; end
% hit test (find node closest to click location: euclidean distnce)
[dst,idx] = min(sum(bsxfun(@minus, pts, p(1,1:2)).^2,2));
if sqrt(dst) > 0.025, return; end
if isempty(prevIdx)
% starting node (requires a second click to finish)
prevIdx = idx;
else
% add the new edge
adj(prevIdx,idx) = 1;
prevIdx = [];
end
end
% update GUI
selectIdx = [];
redraw()
end
function onDelete(~,~)
% check that list of nodes is not empty
if isempty(pts), return; end
% delete selected node
idx = get(h.list, 'Value');
pts(idx,:) = [];
adj(:,idx) = [];
adj(idx,:) = [];
% clear previous selections
if prevIdx == idx
prevIdx = [];
end
selectIdx = [];
% update GUI
set(h.list, 'Value',max(min(idx,size(pts,1)),1))
redraw()
end
function onClear(~,~)
% reset everything
prevIdx = [];
selectIdx = [];
pts = zeros(0,2);
adj = sparse([]);
% update GUI
set(h.list, 'Value',1)
redraw()
end
function onExport(~,~)
% export nodes and adjacency matrix to base workspace
assignin('base', 'adj',(adj+adj')>0) % make it symmetric
assignin('base', 'xy',pts)
end
function onSelect(~,~)
% update index of currently selected node
selectIdx = get(h.list, 'Value');
redraw()
end
function onCMenu(~,~)
% flip state
showLabels = ~showLabels;
redraw()
end
function redraw()
% edges
p = nan(3*nnz(adj),2);
[i,j] = find(adj);
p(1:3:end,:) = pts(i,:);
p(2:3:end,:) = pts(j,:);
set(h.edges, 'XData',p(:,1), 'YData',p(:,2))
% nodes
set(h.pts, 'XData',pts(:,1), 'YData',pts(:,2))
set(h.prev, 'XData',pts(prevIdx,1), 'YData',pts(prevIdx,2))
set(h.selected, 'XData',pts(selectIdx,1), 'YData',pts(selectIdx,2))
% list of nodes
set(h.list, 'String',num2str(pts,'(%.3f,%.3f)'))
% node labels
if ishghandle(h.txt), delete(h.txt); end
if showLabels
set(h.menu, 'Checked','on')
h.txt = text(pts(:,1)+0.01, pts(:,2)+0.01, ...
num2str((1:size(pts,1))'), ...
'HitTest','off', 'FontSize',8, ...
'VerticalAlign','bottom', 'HorizontalAlign','left');
else
set(h.menu, 'Checked','off')
end
% force refresh
drawnow
end
end
这一切都归结为处理轴对象的ButtonDownFcn
回调,并使用CurrentPoint
属性查询最后一次鼠标单击的位置。
以下是与 GUI 交互的可能方式的列表:
“导出”按钮在包含顶点二维坐标(N×2 矩阵)和边(作为稀疏 N×N 矩阵)的基础工作区中创建两个变量。您可以像往常一样将这些变量与其他图形函数一起使用:
gplot(adj, xy, 'b.-')
最后,您可以右键单击列表框。这将弹出一个弹出菜单,其中包含显示顶点标签的选项。
您可以扩展上述代码以将值分配给顶点。例如,您可以使用列表框的回调函数为顶点分配值(当用户从列表中选择项目时显示输入对话框)。ButtonDownFcn
您还可以使用显示的处理回调的相同技术。同样,您可以创建第二个列表框来显示边缘并以相同的方式处理值的分配......我将这部分交给你:)