How to resize axes programmatically within a GUI built with uifigure and uigridlayout?

Hi everyone,
I've been building a GUI based on a uifigure and the matlab.apps.AppBase tools. It's not built in App Designer, I do it programmatically. I use a uigridlayout to position my various items; it works quite well for most things, but I'm having trouble with uiaxes.
These uiaxes are located within the uigridlayout, but I need to make a slight size adjustment after they've been created. I just need to adjust the width, I know by how many pixels to adjust it. If I run my app by typing "app = appName();" in the command window, the app shows up, the uiaxes are not adjusted. I then issue the command in the command window: "app.myAxes.Position(3) = app.myAxes.Position(3) - boxWidth;", which does exactly what I need it to do.
However, adding that line of code in the code that builds the actual GUI does not work, no matter where I try to put it. I've set AutoResizeChildren of the uifigure to off, no luck. I've searched here, but nothing I found seems to work.
So how do I get my app to execute that particular line of code?
Cheers,
Christiane

8 commentaires

Attach a minimum working example so folks can play around with it; unfortunately, the forum doesn't support the uifigure so it can't be checked out here.
drawnow is sometimes required to force updating the HG2 figures; I dont know if it is effective with the uifigure or not, but you could try adding one after the resizing code line to see...
Alternatively, try
pos=app.myAxes.Position;
pos(3)=pos(3)-boxWidth;
app.myAxes.Position=pos;
Hi dpb,
Those were the exact lines of code I was trying to get my program to execute. I've tried drawnow, didn't seem to make any difference whatsoever. Here's a working code you can use to play with:
classdef myGUI < matlab.apps.AppBase
properties
fGUI;
axesGTextes;
axesDTextes;
boxWidth;
backgroundcolor;
end
methods
function app = myGUI()
app.fGUI = uifigure('Units', 'Pixels', 'Position', [0 0 720 650]);
movegui(app.fGUI, 'center');
nbColumns = 8;
nbRows = 17;
mainGrid = uigridlayout(app.fGUI, [nbRows+2 nbColumns*2+2], ...
'Padding', [10 0 0 0], 'RowSpacing', 0, 'ColumnSpacing', 0);
mainGrid.RowHeight{1} = '5x';
mainGrid.RowHeight{end} = '3x';
mainGrid.ColumnWidth{nbColumns+1} = '3x';
mainGrid.ColumnWidth{end} = '3x';
for iRow = 1:nbRows
rowLabel = uilabel(mainGrid, 'Text', ['Row ' num2str(iRow)], 'HorizontalAlignment', 'center');
rowLabel.Layout.Row = iRow + 1;
rowLabel.Layout.Column = nbColumns + 1;
for iCol = 1:nbColumns
impGCheck = uicheckbox(mainGrid, 'Text', '');
impGCheck.Layout.Row = iRow + 1;
impGCheck.Layout.Column = nbColumns + 1 - iCol;
impDCheck = uicheckbox(mainGrid, 'Text', '');
impDCheck.Layout.Row = iRow + 1;
impDCheck.Layout.Column = nbColumns + 1 + iCol;
end
end
app.backgroundcolor = [0.95 0.95 0.95];
app.axesGTextes = uiaxes(mainGrid, 'XColor', app.backgroundcolor, 'YColor', app.backgroundcolor, ...
'XLim', [1 nbColumns], 'XTickLabel', {}, 'YTickLabel', {});
app.axesGTextes.Layout.Row = 1;
app.axesGTextes.Layout.Column = [1 nbColumns];
app.axesDTextes = uiaxes(mainGrid, 'XColor', app.backgroundcolor, 'YColor', app.backgroundcolor, ...
'XLim', [1 nbColumns], 'XTickLabel', {}, 'YTickLabel', {});
app.axesDTextes.Layout.Row = 1;
app.axesDTextes.Layout.Column = [nbColumns+2 length(mainGrid.ColumnWidth)-1];
for iCol = 1:nbColumns
impTextG = text(nbColumns+1-iCol, 0, ['Column ' num2str(iCol)], 'Rotation', 60, 'Parent', app.axesGTextes); %#ok<NASGU>
impTextD = text(iCol, 0, ['Column ' num2str(iCol)], 'Rotation', 60, 'Parent', app.axesDTextes); %#ok<NASGU>
end
app.boxWidth = 25;
% These two lines of code don't seem to be executed at all, or
% the result doesn't stick
app.axesGTextes.Position(3) = app.axesGTextes.Position(3) - app.boxWidth;
app.axesDTextes.Position(3) = app.axesDTextes.Position(3) - app.boxWidth;
end
function ResizeTextAxes(app)
app.axesGTextes.Position(3) = app.axesGTextes.Position(3) - app.boxWidth;
app.axesDTextes.Position(3) = app.axesDTextes.Position(3) - app.boxWidth;
end
end
end
You can start the app through the command line; if you execute the ResizeTextAxes from the command window, it'll work. If you issue the two resizing commands from the command window, it works. But the program just doesn't seem to execute those lines, or else there's another function that resizes the GUI after I've issued them.
Sorry for pasting the code within the text answer, I seem to be having problems with the forum interface. Hope it posts better that way...
classdef myGUI < matlab.apps.AppBase
properties
fGUI;
axesGTextes;
axesDTextes;
boxWidth;
backgroundcolor;
end
methods
function app = myGUI()
app.fGUI = uifigure('Units', 'Pixels', 'Position', [0 0 720 650]);
movegui(app.fGUI, 'center');
nbColumns = 8;
nbRows = 17;
mainGrid = uigridlayout(app.fGUI, [nbRows+2 nbColumns*2+2], ...
'Padding', [10 0 0 0], 'RowSpacing', 0, 'ColumnSpacing', 0);
mainGrid.RowHeight{1} = '5x';
mainGrid.RowHeight{end} = '3x';
mainGrid.ColumnWidth{nbColumns+1} = '3x';
mainGrid.ColumnWidth{end} = '3x';
for iRow = 1:nbRows
rowLabel = uilabel(mainGrid, 'Text', ['Row ' num2str(iRow)], 'HorizontalAlignment', 'center');
rowLabel.Layout.Row = iRow + 1;
rowLabel.Layout.Column = nbColumns + 1;
for iCol = 1:nbColumns
impGCheck = uicheckbox(mainGrid, 'Text', '');
impGCheck.Layout.Row = iRow + 1;
impGCheck.Layout.Column = nbColumns + 1 - iCol;
impDCheck = uicheckbox(mainGrid, 'Text', '');
impDCheck.Layout.Row = iRow + 1;
impDCheck.Layout.Column = nbColumns + 1 + iCol;
end
end
app.backgroundcolor = [0.95 0.95 0.95];
app.axesGTextes = uiaxes(mainGrid, 'XColor', app.backgroundcolor, 'YColor', app.backgroundcolor, ...
'XLim', [1 nbColumns], 'XTickLabel', {}, 'YTickLabel', {});
app.axesGTextes.Layout.Row = 1;
app.axesGTextes.Layout.Column = [1 nbColumns];
app.axesDTextes = uiaxes(mainGrid, 'XColor', app.backgroundcolor, 'YColor', app.backgroundcolor, ...
'XLim', [1 nbColumns], 'XTickLabel', {}, 'YTickLabel', {});
app.axesDTextes.Layout.Row = 1;
app.axesDTextes.Layout.Column = [nbColumns+2 length(mainGrid.ColumnWidth)-1];
for iCol = 1:nbColumns
impTextG = text(nbColumns+1-iCol, 0, ['Column ' num2str(iCol)], 'Rotation', 60, 'Parent', app.axesGTextes); %#ok<NASGU>
impTextD = text(iCol, 0, ['Column ' num2str(iCol)], 'Rotation', 60, 'Parent', app.axesDTextes); %#ok<NASGU>
end
app.boxWidth = 25;
% These two lines of code don't seem to be executed at all, or
% the result doesn't stick
app.axesGTextes.Position(3) = app.axesGTextes.Position(3) - app.boxWidth;
app.axesDTextes.Position(3) = app.axesDTextes.Position(3) - app.boxWidth;
end
function ResizeTextAxes(app)
app.axesGTextes.Position(3) = app.axesGTextes.Position(3) - app.boxWidth;
app.axesDTextes.Position(3) = app.axesDTextes.Position(3) - app.boxWidth;
end
end
end
I have only done the few apps I've done through appdesigner and they have barebones minimal components so I'm not a good one for more complex things. But, your comment
" But the program just doesn't seem to execute those lines, or else there's another function that resizes the GUI after I've issued them."
is sorta' what I'm thinking must be going on behind the scenes; have you tried setting a breakpoint in the app after the resize call to see if, indeed, it is getting executed and the change happens but then gets blown away later by something behind the scenes? If it functions as expected from command line and not in the application code, then it has to be something between the two; if it were first done and then lost, that would tell you something, at least, even if not yet a solution.
Secondly, I wonder about the grid layout container possibly being the culprit; have you tried programmatically building a test application that does the single component and resizes it and get it to work, then keep adding pieces around it until you break it?
Failing that any of those options help, it's probably time to submit the MWE to official support if somebody doesn't come along "real soon now"...
Hi again,
It does the exact same thing even with just the uifigure and one uiaxes. I called the resize method from the constructor an added a "disp" command to it to check if it was getting executed: yup, it's getting executed, just doesn't work.
Actually, if I add a breakpoint within the app, the size change will be applied and it will stick. The exact same code, no changes anywhere. So it's starting to look a lot like a bug... I'll submit it to official support.
Thanks for trying!
dpb
dpb le 12 Sep 2024
Modifié(e) : dpb le 12 Sep 2024
I don't know what is different in your class for the app built programmatically, but I just build an app w/ appbuilder consisting of an axes and a button; the button call back was to reduce the axes width by 25% each time it was pressed.
That functioned as expected, so there's something going on in the way appbuilder builds one and your version. I did it under R2021b, however, so I suppose it's possible some bug got introduced since.
See if the below has the same/similar issue on your system...
Indeed, there are probably significant differences in your code and an appdesigner-created one...
classdef myGUI < matlab.apps.AppBase
properties
fGUI;
axesGTextes;
axesDTextes;
boxWidth;
backgroundcolor;
end
methods
function app = myGUI()
The appdesigner mini app I posted looks like
lassdef testResizeUIAxes_exported < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
Button matlab.ui.control.Button
UIAxes matlab.ui.control.UIAxes
end
% Callbacks that handle component events
methods (Access = private)
% Button pushed function: Button
function ButtonPushed(app, event)
pos=app.UIAxes.Position;
pos(3)=0.75*pos(3);
app.UIAxes.Position=pos;
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
...
I'm guessing if you follow that template, then it will work as expected. In particular, the public properties and way they'r defined I suspect is where the problems lie -- and, a callback function is always expected to have the argument list of (app,event) which you're missing...
If I use a callback function from a button like you do in your template, it works, the resizing gets done. But I have to push the button.
My problem is that I want to do it when I build the GUI; the exact same lines of code, if called from the constructor rather than from a callback function, don't do anything. These same lines of code, if I put a breakpoint after creating the axes, (not before!) will work and be executed within the constructor.
Try and put a breakpoint in the code I posted, and see how the results differ if the breakpoint is after the axes creation. Tell me it's not a bug...

Connectez-vous pour commenter.

Réponses (1)

dpb
dpb le 12 Sep 2024
Modifié(e) : dpb le 13 Sep 2024
Here's a start; I needed a break from other issues of the day so I began to reorganize in line with the appdesigner layout, but it didn't seem to make any real difference, somewhat to my surprise.
However, since it worked to reduce the size of an UIAxes in a figure; I'm thinking it must have something to do with it being in a grid layout and somehow what that does/displays. --- Oh, one other thought...well, that didn't work, either. I thought maybe if one deleted the axes and then recreated it with the new size, but no; it used the new size but was still rendered the same as before. I'm pretty sure this must have something to do with how grids work but I've never used one so know absolutely nothing about their intricacies.
But, here's a file rearranged to be more in line with appdesigner structure; unfortunately, it didn't seem to make any difference in the symtpoms.

Catégories

En savoir plus sur Develop Apps Using App Designer dans Centre d'aide et File Exchange

Produits

Version

R2023a

Modifié(e) :

dpb
le 13 Sep 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by