Reliably resize uifigure - sometimes set Position is ignored under test automation

Hi,
I'm facing a strange issue, where resizing of a uifigure doesn't work consistently under testautomation stress.
Maybe someone has a tip for me, is there a better way to ensure that fig.Postion = [something] is visually applied, than drawnow/pause?
I have set of complicated dialogs, where frames needs to be extended to accomodate additional controls, when user clicks something. Everything works OK for manual testing, but starts failing on test automation.
I have a class object, representing the dialog, and it has property "mainFigure" - uifigure. For resizing of it (extra space on the lower part) I've implemented method
function pos = increaseMainFigureHeight(obj, increase)
pos = obj.mainFigure.Position;
% move bottom
pos(2) = pos(2) - increase;
% and increase the height
pos(4) = pos(4) + increase;
obj.mainFigure.Position = pos; <<<
% Flush callbacks and allow layout/window to settle before asserting position
desiredPos = pos;
for k = 1:60
drawnow;
if isequal(obj.mainFigure.Position, desiredPos) <<<<< this read may return different value!
disp(['increase ok: ' num2str(k)]);
break;
end
pause(0.05);
end
if k>=60
Messaging.debug('Figure height update not solved in 60 rounds', level=Messaging.Warning);
end
end
And very similar for decrease the height.
Under manual conditions the "disp(['increase ok: ' num2str(k)]);" prints always 1 - after setting new positions and drawnow, reading of the position will correspond to the positions, which were just set!
However, as soon as I get it under testautomation:
classdef ReusableDialogTest < matlab.unittest.TestCase
methods (Test)
function testIncreaseDecreaseMainFigureHeight(testCase)
dlg = dialogs.AIConfigDialog(); % Just create some dialog, inherited from ReusableDialog
clp = onCleanup(@() delete(dlg));
increaseSize = 100;
initialPos = dlg.mainFigure.Position;
extendedPosition = initialPos;
extendedPosition(2) = initialPos(2) - increaseSize;
extendedPosition(4) = initialPos(4) + increaseSize;
for repeat = 1:20
dlg.increaseMainFigureHeight(increaseSize);
testCase.assertEqual(dlg.mainFigure.Position, extendedPosition);
dlg.decreaseMainFigureHeight(increaseSize);
testCase.assertEqual(dlg.mainFigure.Position, initialPos);
end
end
end
end
I'm starting getting problems.
Note: I've inserted the loop for 20 repetitions, just to make the issue more visible.
Typical output for running the test will look like:
Running ReusableDialogTest
Setting up ReusableDialogTest
Done setting up ReusableDialogTest in 0 seconds
Running ReusableDialogTest/testIncreaseDecreaseMainFigureHeight
increase ok: 3
decrease ok: 1
increase ok: 2
decrease ok: 1
increase ok: 2
decrease ok: 2
...
So, sometimes several rounds of drawnow/pause are required.
But sometimes it stucks completely. In following case decrease didn't succeed with 60 hops of drawnow/pause:
Running ReusableDialogTest
Setting up ReusableDialogTest
Done setting up ReusableDialogTest in 0 seconds
Running ReusableDialogTest/testIncreaseDecreaseMainFigureHeight
increase ok: 3
Warning: Figure height update not solved in 60 rounds
================================================================================
Assertion failed in ReusableDialogTest/testIncreaseDecreaseMainFigureHeight and it did not run to completion.
---------------------
Framework Diagnostic:
---------------------
assertEqual failed.
--> The numeric values are not equal using "isequaln".
--> Failure table:
Index Actual Expected Error RelativeError
_____ ______ ________ _____ __________________
2 478 578 -100 -0.173010380622837
4 252 152 100 0.657894736842105
Actual Value:
729 478 583 252
Expected Value:
729 578 583 152
------------------
Stack Information:

 Accepted Answer

Thanks to the ideas of @dpb, I've implemented a workaround, which seems to be stable enough - in my tests yet never failed.
Idea is based on the empirical data:
  • Making some pauses will assure that the change of figure size is applied
  • In some rare situation (my observation is ~1-2% under test automation with fast, repetitive change of figure size), change of the size won't succeed even after several pauses.
  • I've seen that on my Macbook Pro, 64GB RAM and MATLAB R2025b U3 amount of pauses of 0.05 secs don't exceed 4 for successful application of the size (0.2 sec in total). If it takes longer, then the whole procedure will fail and position of the uifigure won't change anymore
Workaround is trivial - try to set the Position again couple times.
Here is the whole text of the method to resize figure with debug outputs (could be further optimized, I guess, so it's just a reference):
function increaseHeight(~, fig, increase)
pos = fig.Position;
% move bottom and increase height
pos = pos + increase * [0 -1 0 1];
desiredPos = pos;
successfullyApplied = false;
% Set position 1 time, if fails try another couple times
for resizeAttempts = 1:3
fig.Position = pos;
drawnow;
% Flush callbacks and allow layout/window to settle before asserting position
for k = 1:10
pause(0.05);
if isequal(fig.Position, desiredPos)
if increase > 0
disp(['increase ok: ' num2str(k)]);
else
disp(['decrease ok: ' num2str(k)]);
end
break;
end
end
if k>=10
disp('Figure height update not solved in 10 rounds');
else
successfullyApplied = true;
end
if successfullyApplied
break;
end
end
if ~successfullyApplied
warnning('setting size failed');
else
if resizeAttempts > 1
warning(['setting of size succeeded on ' num2str(resizeAttempts) ' attempt']);
else
disp(['setting of size succeeded on ' num2str(resizeAttempts) ' attempt']);
end
end
end
Running in a repetitive tests this produce output like following:
Running ResizingTest
increase ok: 3
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 2
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
Figure height update not solved in 10 rounds
decrease ok: 1
Warning: setting of size succeeded on 2 attempt
> In ResizingTest/increaseHeight (line 112)
In ResizingTest/resize (line 65)
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
increase ok: 1
setting of size succeeded on 1 attempt
decrease ok: 1
setting of size succeeded on 1 attempt
.
Done ResizingTest

7 Comments

I still don't quite follow what the intent here is of why doing this, but ...
If the failures are being induced by putting a call to resize the figure in a tight loop just for the purpose of testing, then I thnk the better way to construct the test is to put a minimal delay in the calling loop after the resize operation completed BEFORE the next attempt in order to allow any internal race condtions to be cleared before initiating another change(*).
If you can observe this behavior in a user app with just normal user interaction, then there's definitely something else going on behind the scenes to cause a queued event to not get processed.
(*) Further reflection -- I wonder if the issue is the same as the read operation of the new position not being updated in time except the other direction -- the symptom would be as though occasionally the queued "change position" variable isn't getting updated when read internally and so the event actually is never in the queue. If that can actually happen under normal circumstances, that's a bug.
If you can build a test case that shows this occurring in normal operation, I think that's worthy of a support request after a careful scrutiny of the code to be sure somewhere there isn't buried a similar tight loop that should be modified.
Thanks @dpb!
> If the failures are being induced by putting a call to resize the figure in a tight loop just for the purpose of testing, then I thnk the better way to construct the test is to put a minimal delay in the calling loop after the resize operation completed BEFORE the next attempt
Yes, that's exactly what I do based on your advices. In the "answer" post, I just added an extra loop on top. But after each drawnow, there is at least a small delay before any comparison is done.
> after the resize operation completed BEFORE the next attempt in order to allow any internal race condtions to be cleared before initiating another change
Well, that's exactly the purpose of the method - to ensure that the resizing is completed, before any further logic on the main thread will be executed. There should not be any "decreaseSize" called, before "increaseSize" is fully completed, and new coordinates are applied.
> I still don't quite follow what the intent here is of why doing this
I didn't want to test setting of Positions at all - that's MW business. However, I have a testsuite with ca. 1000 tests, some of them are UI tests. And in UI I have some dialogs, which resizes automatically, depending on the user selection. For example, I have a "Server Configuration" dialog, where multiple servers are registered in a listview, when user clicks on one of the servers, dialog extends to accomodate properties of the server (and each server might have different set of fields to be shown). When user closes the dialog, I want to preserve its coordinates, thus next time user will see the dialog at the same position, where he left. And for this purpose, I need to close those additional fields first (or simply consider extra size), and save the position, as after reopening, there will be no selection in the listview, thus no extra fields shown.
And I recognized, that sometimes the tests failing, as the dialog was not resized correctly - either the extra space is not allocated, or after closing extra fields and resizing, the "extended" positions for the dialog are saved.
> If you can build a test case that shows this occurring in normal operation
That's what I did in the attached test to my comment on Feb 14th: https://www.mathworks.com/matlabcentral/answers/uploaded_files/1846450/ResizingTest.m
Or did I miss your point?
I was driving at whether it has ever failed the first test -- if not, then ensure some time before a subsequent to see if can isolate it in being a race condition on the request similar to what is seen on the read -- that the size change request when it does fail is because a change actually never did get into the queue.
I don't disagree that it appears the issues are internal and that if the above supposition doesn't help it's probably a bug.
Have you submitted a support request?
> whether it has ever failed the first test
Never seen issue on the very first attempt.
However, increasing of pause to 1sec (which made in total 60 secs waiting time in loop of pauses) didn't change anything - still resizing sometimes was not applied, the figure remained with the old size.
> Have you submitted a support request?
Case 08478402
OK, just a thought. It makes it appear there really is something going on internally -- whether Mathworks will be able to track it down or not may be the issue here, but probably no short term fix.
I am unaware of any undocumented way to query the content of the events queue to see if the event did actually get posted; I suspect only Mathworks can delve that deep into the bowels.
Strange, indeed. Good luck...
I've got some answers from Support:
> We were able to reproduce the sporadic failure and see this as a bug and the development team is working on fixing it for future updates and releases
And
> Use Eventually to wait on a value to settle instead of the for loop.
> Notes:
> - A couple of import are needed (please see the attached ResizingTest_modified.m).
> - the first input of verifyThat must be something that get re-evaludated everytime, not a variable value.
testCase.verifyThat(@() fig.Position, ...
Eventually(IsEqualTo(initialPosition, 'Within', AbsoluteTolerance(1)), ...
'WithTimeoutOf', 10), ...
'Figure Position did not reach the initialPosition value.');
dpb
dpb on 21 Feb 2026 at 14:15
Edited: dpb on 21 Feb 2026 at 18:03
OK, that confirms although it doesn't say precisely the underlying cause but that something like the race condition is occurring internally as suspected and it is a bug.
It would be interesting and I think worthwhile to post the revised code and import for archival purposes and for any who may stumble on this thread because this is not the only case of the read failing

Sign in to comment.

More Answers (1)

There's <another current thread of similar symptom> that is known that occasionally one will get back the unchanged coordinates on an immediate query even after the object has been rendered owing to internal latency of the variable memory locations being updated to reflect the changes before the memory read occurs. I've never seen it take more than just a few 10s of msec however.
I'd recast the update function a little, however. Don't keep forcing the re-rendering; you've already told it once, you're starting it all over when demanding it again. That isn't necessary and is probably not a wise thing to do, you'll be stackng events faster than the rendering engine will be able to handle them and with drawnow alone, they'll all be queued. (It's a lot like code seen pretty often asserting "hold on" inside a loop--once set, 'on' can't get any 'on-er'). At worst, use the 'limitrate' and 'nocallbacks', but since you're not actually needing to change the new position again, just be patient and let it do its thing in its own sweet time...it would be agoodthing™ if Mathworks could figure out a way to prevent this race condtion internally so it didn't occur, but so far it is "just the way it is".
See if the following is any more better...
function pos = increaseMainFigureHeight(obj, increase)
pos = obj.mainFigure.Position;
pos=pos+increase*[0 -1 0 1]; % move bottom and increase height - my idiomatic way to write
%pos=pos+[0 -increase 0 increase]; % alternate idiom using the variable twice but w/o multiplication
desiredPos = pos; % save new location wanted
obj.mainFigure.Position = pos; % set the new
drawnow; % force rendering
for k = 1:60
pause(0.05); % wait a little before querying
if isequal(obj.mainFigure.Position, desiredPos) % make sure memory is updated, too
disp(['increase ok: ' num2str(k)]);
return; % everything is ok, we're done here
end
end
% if here, things went south
Messaging.debug('Figure height update not solved in 60 rounds', level=Messaging.Warning);
end
You potentially could make it more responsive by moving the pause statement to the end of the for...end loop; in the cases in which the race condition doesn't exist it would get by without the delay at all. Be interesting to see how the statistics might change between the two structurings.
If you can still make this fail, then it may take some more in-depth digging about whether the testing regimen you've established is causing something else to go on.

4 Comments

The only thing I can see that could cause a failure in the above other than an internal bug is the outside possibility of the position vector being non-integral values such that the floating point comparison fails. Since MATLAB will accept a double for the position property, if the positions were being calculated from some formula rather than being entered as integer numbers, it is then possible there could be internal rounding. While MATLAB will render the figure rounding the values to nearest pixel, internally the 'Position' property would reflect the values passed in. That could lead to a later failure in an exact comparison if the new position values were calculated/set in a different manner.
That could be avoided if it were assured the values passed initially were always rounded first.
Not likely one would presume, but at least possible.
Thank you very much, @dpb, for your interest on the case and your advices!
Unfortunately, even with your changes I didn't get the reliable resizing - sometimes the uifigure simply stays in the original position, nothing happens anymore.
It's also doesn't seem as a rounding issue, as - see testrun result - the actual position differ exactly by 100 in bottom/height, not something small/unequal.
Moving pause from the beginning of the loop to end of it changes the statistics (I'd say in expected way, as extra 0.05s at the beginning gives rendering engine more time to complete the work before validation):
Here is typical output in console, when pause is at the beginning:
Running ReusableDialogTest
Setting up ReusableDialogTest
Done setting up ReusableDialogTest in 0 seconds
Running ReusableDialogTest/testIncreaseDecreaseMainFigureHeight
increase ok: 1
decrease ok: 3
increase ok: 1
decrease ok: 1
increase ok: 1
decrease ok: 1
...
most further loops will be also completed on the first attempt ("1").
Here is typical output in console, when pause is at the end:
Running ReusableDialogTest
Setting up ReusableDialogTest
Done setting up ReusableDialogTest in 0 seconds
Running ReusableDialogTest/testIncreaseDecreaseMainFigureHeight
increase ok: 2
decrease ok: 1
increase ok: 1
decrease ok: 2
increase ok: 2
decrease ok: 1
increase ok: 1
decrease ok: 2
...
In both cases, seldomly I see "3" or "4", but never 20 or 30, and sometimes it simply stucks for 3sec (0.05*60), dialog remains unchanged (e.g. if I set a breakpoint, where the message about 60 loops is printed - no further changes to its size will be ever applied).
Please note, that I implemented that "stress test" only for the reason, that resizing of the dialog fails sporadically in a big test suite in a single run (no repetitions of the resizing, whatsoever), therefore I've implemented the loop in the "increase/decrease" method to continue after resizing is assured. And wanted to test if this will bring the reliability, which appeared to be harder, than I expected.
Now, coming to the most interesting part, related to the execution of the test automations.
I'm attaching an isolated test without any dependency on my project.
It creates a figure, and tries to resize it.
With empty figure it works smooth and great.
Then I asked copilot to generate a complex layout and controls in the lines 11-60.
The situation changed.
On my first attempts to run the test via:
runtests("ResizingTest")
I was getting statistics, that sometimes it takes longer time (resizing was not from the first attempt), but then most of the time it was "1":
>> runtests("ResizingTest")
Running ResizingTest
increase ok: 3
decrease ok: 1
increase ok: 1
decrease ok: 1
increase ok: 1
decrease ok: 1
increase ok: 1
decrease ok: 1
increase ok: 1
...
However, after some time (no changes, just running theses tests over and over again), I've started to get "stuck" things more and more often:
>> runtests("ResizingTest")
Running ResizingTest
increase ok: 3
decrease ok: 1
increase ok: 1
decrease ok: 1
Figure height update not solved in 60 rounds
================================================================================
Verification failed in ResizingTest/resize.
---------------------
Framework Diagnostic:
---------------------
verifyEqual failed.
--> The numeric values are not equal using "isequaln".
--> Failure table:
Index Actual Expected Error RelativeError
_____ ______ ________ _____ _________________
2 400 300 100 0.333333333333333
4 300 400 -100 -0.25
Actual Value:
400 400 600 300
Expected Value:
400 300 600 400
------------------
Stack Information:
------------------
In /Users/entin/Projects/LocalGit/ReQonsult/ResizingTest.m (ResizingTest.resize) at 64
================================================================================
decrease ok: 1
On my machine it's most visible (Macbook Pro M2, 64GB, MATLAB R2025b U3), if I run the test several times, like that:
for x=1:10, runtests('ResizingTest'), end
then at least one of them will fail for me.
Note: Increase of the loop inside of the test won't change much - is it 20 loops of increase or 100, doesn't matter.
Note2: i also tried to increase the pause to 1sec instead of 0.05 - it also didn't change much. Sometimes, the position is not changed.
I'll post Support Ticket for that, maybe we'll hear something.
There have been quite a few reports of rendering issues on Mac and Linux so perhaps this is another symptom.
Have you tried the 'SizeChangedFcn' callback to see if it is always being generated? I'm not sure where in the hierarchy chain it is triggered; whether it might not be in the failing cases or if it were but the rendering still didn't occur might be a clue.
Sounds as though there is something internal going on, however...is there anything else happening during these tests that could switch focus or the like?
> Have you tried the 'SizeChangedFcn' callback to see if it is always being generated?
Well, I tried, but as soon as I register "SizeChangedFcn" callback for the figure, I'm getting warning:
Warning: 'SizeChangedFcn' callback will not execute while 'AutoResizeChildren' is set to 'on'.
I didn't dig further.
> is there anything else happening during these tests that could switch focus or the like?
I've attached fully isolated test in my long comment above - there is nothing happening in the code, except of creation of the figure, and changing it's size. I have no idea if test execution framerwork ("runtests") is doing anything on UI level. Visually, there is nothing.

Sign in to comment.

Categories

Find more on Programming Utilities in Help Center and File Exchange

Products

Release

R2025b

Asked:

on 12 Feb 2026

Edited:

dpb
on 21 Feb 2026 at 18:03

Community Treasure Hunt

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

Start Hunting!