Quite simply, I'm trying to create a borderless button in a MATLAB GUI. The reasons are mostly aesthetics, so no need for a debate on why it should be borderless.
I already know that this cannot be done using the built-in MATLAB uicontrol alone, since the border of the button is not an accessible property in MATLAB. Thus, the underlying JAVA code (upon which MATLAB is written), must be accessed in order to manipulate the border. This is where I get lost, since I've only ever programmed in MATLAB.
I followed an example from here:
http://undocumentedmatlab.com/blog/borderless-button-used-for-plot-properties
But I'm still not getting a borderless button.
Here is a simple code example (NOTE the use of Yair Altman's findjobj which is available on the MATLAB file exchange):
f=figure('Menubar','none', 'Position',[200 200 300 200]);
p=uipanel(f, 'BackgroundColor', [0 0 1]);
h = uicontrol('parent', p, ...
'Style','pushbutton', ...
'String','click', ...
'TooltipString', 'you should click this' ...
'Units','normalized', ...
'Position',[0.3 0.3 0.5 0.5], ...
'BackgroundColor', [0 0 1]);
jh = findjobj(h);
jh.setBorder(javax.swing.BorderFactory.createEmptyBorder());
%attempt 1 does not remove border
jh.border=[];
%attempt 2 does not remove border
jh.setBorder([]);
%attempt 3 does not remove border
jh.border=javax.swing.BorderFactory.createEmptyBorder();
%attempt 4 does not remove border
Any thoughts on where I've gone wrong? Thanks!
You shoud add two lines:
jh.setBorderPainted(false);
jh.setContentAreaFilled(false);
It is not clear to me what you mean with "borderless".
Looking at the example on the Web page you posted, I assume you are looking for something like an "invisible" pushbutton.
If so, you might consider this alternative way:
insted of having a pushbutton you might have a static text uicontrol
make its backgroundcolor the same of the GUI backgroundcolor (it will become "invisible" and without any border)
do not set any string in the static text uicontrol
set the enable property of the static text uicontrol to off
define, for the static text uicontrol the ButtonDownFcn
write the code you want to execute by pushing the pushbutton in the ButtonDownFcn
When you press the mouse button on the "invisible" static text uicontrol, its ButtonDownFcn will be executed.
You just have to remember ... were the "invisible" static text uicontrol is.
Hope this helps.
The border is affected by the fly-over appearance feature. http://undocumentedmatlab.com/blog/undocumented-button-highlighting
You need to add
jh.setFlyOverAppearance(true);
Worked for me.
Related
How do I check if a slider in a MATLAB GUI have been used, i.e. the user have interacted with the slider?
The slider is given by the following GUI code:
uicontrol(fig,'Style','Slider','Units','characters','Position',[17.1+f*iwidth 10.5 8 59.6],'Min',0,'Max',1000,'Value',500,'SliderStep', [1/500 , 20/500 ],'Tag',['slider' int2str(f)]);
Is there a clever way of doing this?
The only thing you need to add is a callback function. You can add it with the same uicontrol command.
uicontrol(fig,'Style','Slider','Units','characters','Position',[17.1+f*iwidth 10.5 8 59.6],'Min',0,'Max',1000,'Value',500,'SliderStep', [1/500 , 20/500 ],'Tag',['slider' int2str(f)], 'Callback', #myfunc);
then you need to write the myfunc, something like this:
function myfunc(source,event)
value = source.Value % This is the position of the slider
end
I am running the drawnow statement from a callback function within a MATLAB GUI to update the state of a button. At the beginning of the callback (which has high runtime) I alter the properties of the button and force an update with drawnow. While updateing properly, the button remains rendered 'pushed down' instead of 'disabled'. After the callback is finished, the button is updated again and now rendered 'disabled'.
Take following minmal (not) working example:
function simple_example()
h = figure();
% add a button, give it some properties and a callback
uicontrol(h,...
'Style','pushbutton',...
'String','I am enabled',...
'Units','normalized',...
'Position',[0.5 0.5 0.4 0.4],...
'Callback',#btn_callback);
end
function btn_callback(hObject, ~)
set(hObject,'Enable','off');
set(hObject,'String','I am disabled');
drawnow;
pause(3);
end
Is there a way to change this behavior and have the button appear disabled while the callback is still executing?
As you are asking about appearance here's a workaround using uibuttongroup:
function simple_example()
h = figure();
b = uibuttongroup('Position',[0.5 0.5 0.4 0.4]);
bgcolor = b.BackgroundColor;
% add a button, give it some properties and a callback
uicontrol(b,...
'Style','pushbutton',...
'String','I am enabled',...
'Units','normalized',...
'Position',[-0.05 -0.05 1.1 1.1],...
'Callback',#btn_callback);
end
function btn_callback(hObject, ~)
set(hObject,'Enable','off');
set(hObject,'String','I am disabled');
drawnow;
pause(3);
end
Here, you fit the button within a uibuttongroup, which normally groups several uibuttons and then set the button size bigger than the actual uibuttongroup, so the borders don't appear.
However, this let's you lose the button down rendering. You could get that back by altering the uicontrolgroup's border properties.
Update:
This seems to be OS-specific. On OS X your code works just fine, as far as I can see. Windows, I don't know, but according to your comment neither my version, nor yours seems to fix the issue. On Ubuntu, on the other hand, my answer solves the problem.
I have a troubling problem that I've been trying to figure out for quite a while now and I just have no clue why it's happening. I have a self-coded GUI and I have a panel on the main GUI figure. On this panel I have an axes and whenever I plot a bar graph on that axes and try to edit its view with either yLim() or axis(), the axes will be resized to the dimensions I want, but the bar graph will not chop off at the edge of the axes and it will continue to run off the page. After playing around with it for a while in debug mode, I have found out that if I change the axes' parent from the panel it's on to the main figure, the bar graph will properly display only what is inside the axes borders like I want it to. I don't want to use changing the axes' parent as a permanent solution since I have several different panels I want to go between and having an axes on the main figure instead of the panel wouldn't work but I'd like to know if anybody knows why this is happening and how I can fix it.
For example, this code produces the problem I'm experiencing:
mainFig = figure('Units','characters',...
'Position',[40 5 200 50],...
'Color',[100/255 145/255 209/255]);
axesPanel = uipanel('bordertype','etchedin',...
'Parent',mainFig,...
'Title','Axes Panel');
mainAxes = axes('parent',axesPanel,...
'Units','characters');
bar(mainAxes,1:10,1:10)
ylim(mainAxes,[6 10])
And if the axes' parent is changed to be the figure, the problem doesn't exist. This line of code does that:
set(mainAxes,'parent',mainFig)
Thanks for any help or information as to why this is happening!
Just in case anybody else was having this same problem, I contacted MATLAB Technical Support and I was told that this was a bug on MATLAB's end that is being fixed in the next release(R2014b). They said that if you are having the problem I described in my original question, that in order to make the bar graph appear within the axes' boundaries at the moment, that you can edit the figure's 'Renderer' property and set it to either 'opengl' or 'zbuffer'. I have tested this and both options work so hopefully that helps :)
And just for extra clarification if it is needed, all I needed to change from my original code was:
mainFig = figure('Units','characters',...
'Position',[40 5 200 50],...
'Color',[100/255 145/255 209/255]);
To this:
mainFig = figure('Units','characters',...
'Renderer','opengl',...
'Position',[40 5 200 50],...
'Color',[100/255 145/255 209/255]);
And now the bar graph behaves as it should.
I have a strange problem in my Matlab GUI. The GUI contains uipanel and icontrol objects, some of which are buttons. Usually, the GUI is controlled with the directional arrow keys.
However, once I click one of my buttons, the keyboard events are not recorded any more. I've set breakpoints in the keypress callback to find out what's happening and it turns out the callback is never called. If I manage to click the GUI background, it works once again, which makes me think it's related to the active control. But how can I give control back to the main window? uicontrol(hFigure) doesn't work, neither does figure(hFigure).
The following code snippet reproduces the problem. Copy it into a new file (ideally called test.m, otherwise Code Analyzer will complain) and run it to open a GUI window that shows this behaviour. Once the button is clicked, the arrow keys aren't recorded any more unless the user clicks the area outside the text uicontrol.
function test
figure('KeyPressFcn',#key)
clf
p = uipanel('position',[0 0 1 1],'BackgroundColor',[.7 .7 .7]);
uicontrol('Style','push','String','Click me','Units','norm',...
'Position',[0.43 0.91 0.14 0.06],'Callback',#button);
t = uicontrol(p,'Style','text','String','Use arrow keys','Units','norm',...
'Position',[0.2 0.4 0.6 0.2],'FontSize',20);
function button(~,~)
set(t,'String','Button pressed.');
end
function key(~,e)
set(t,'String',['Key ' e.Key ' pressed.']);
end
end
You are right about why this doesn't work. When you click on the button, the figure is no longer the active control. The best way to fix this is to additionally set the KeyPressFcn property of the button to be the same as the KeyPressFcn of the figure.
function test
figure('KeyPressFcn',#key)
clf
p = uipanel('position',[0 0 1 1],'BackgroundColor',[.7 .7 .7]);
uicontrol('Style','push','String','Click me','Units','norm',...
'Position',[0.43 0.91 0.14 0.06],'Callback',#button, ...
'KeyPressFcn', #key);
t = uicontrol(p,'Style','text','String','Use arrow keys','Units','norm',...
'Position',[0.2 0.4 0.6 0.2],'FontSize',20);
function button(~,~)
set(t,'String','Button pressed.');
end
function key(~,e)
set(t,'String',['Key ' e.Key ' pressed.']);
end
end
You could also set the WindowKeyPressFcn instead of KeyPressFcn.
For more information see my answer here:
matlab: difference between KeyPressFcn and WindowKeyPressFcn
I know that one can insert a colorbar by clicking the colorbar icon in the clustergram GUI. Is there a way to do it programmatically?
I tried
cgo = clustergram(data)
colorbar;
This makes a colorbar in a new figure window. How can a colorbar be created with proper positioning in a clustergram figure as if the button was clicked?
There is a function buried away (HeatMap.plot>showColorbar) that neatly positions the colorbar to the left of both the heat map and the dendogram (the lines). Just running colorbar(...) will mess up the relative positioning of the dendogram and the heatmap. So you need to somehow run the callback or carefully duplicate all of the position computations. It's easier to just run the callback. Here's how.
To create the colorbar programmatically for a clustergram, and keep the color bar button in sync, you need to use the button's assigned callback and set the button's state.
Create the clustergram:
load filteredyeastdata
cgo = clustergram(yeastvalues(1:30,:),'Standardize','Row');
Get the handle for color bar button:
cbButton = findall(gcf,'tag','HMInsertColorbar');
Get callback (ClickedCallback) for the button:
ccb = get(cbButton,'ClickedCallback')
ccb =
#insertColorbarCB
[1x1 clustergram]
That gives us a handle to the function assigned by the callback (#insertColorbarCB), and the function's third input argument (the clustergram object). The button's handle and an empty event object are implicitly the first two arguments.
Change the button state to 'on' (clicked down):
set(cbButton,'State','on')
Run the callback to create the colorbar:
ccb{1}(cbButton,[],ccb{2})
Note that the button State must be changed to 'on' first, otherwise the callback won't do anything.
I just managed to solve this problem.
What I did:
I added this function to the clustergram code (I put it at line 1486)
%%%%%%%%%%%%%%
function insertColorbarCBALWAYS(obj)
hFig= gcbf;
obj.Colorbar = true;
end
%%%%%%%%%%%%%%%
and then at line 415 of the clustergram.m file I added this line of code
insertColorbarCBALWAYS(obj);
to call the above function. Save and go: now the colorbar will always be there, once the clustergram is drawn.
Previous method was not working for me so I made this workaround.
One may even save the new clustergram code as clustergramCM such that you can draw cgram in both ways.