StackOverflowMATLABchat / mlapptools

MATLAB class containing methods for programmatic uifigure modification
http://undocumentedmatlab.com/blog/customizing-uifigures-part-2
MIT License
25 stars 11 forks source link

UITable unsupported #15

Open t2m4k1 opened 6 years ago

t2m4k1 commented 6 years ago

Expected Behavior

Hello together,

my ultimate goal is to change the background color of a single column in a uitable. Therefore I'd like to modify the uitable's style. Is this currently possible / will it be supported in a future release of mlapptools? I attached a little code-sample showing that even basic operations on uitables are currently not working for me.

Thanks in advance,

Thomas

Actual Behavior

Warning: This widget is unsupported. In mlapptools/getWidgetID (line 390) In mlapptools.getWebElements (line 134) In mlapptools.fontColor (line 70) Output argument "ID_obj" (and maybe others) not assigned during call to "mlapptools/getWidgetID".

Error in mlapptools.getWebElements (line 134) widgetID = mlapptools.getWidgetID(win, mlapptools.getDataTag(uiElement));

Error in mlapptools.fontColor (line 70) [win, ID_struct] = mlapptools.getWebElements(uiElement);

Steps to Reproduce the Problem

uiFig = uifigure(); mlapptools.setTimeout(uiFig,15); tbl = uitable(uiFig); mlapptools.fontColor(tbl, 'aqua');

Specifications

Dev-iL commented 6 years ago

Did you see the provided Table Demo for an example of how to edit tables?

A table is actually a collection of many different elements (mainly headers and cells), each with its own handle. I know of no way to modify a collection of cells (in this case a column) in one go - you'll have to find handles to every individual cell and update each of them separately, as is done in the demo.

I'll look into this to see if there's a way to do what you want...

t2m4k1 commented 6 years ago

Thanks a lot! The table demo only changes the border of the modify button to red after clicking it. I get no error messages and nothing else happens. I've tried to understand the mlapptools.m code and was experimenting with the code of the demos and had success with things like adding transparency to buttons by using setStyle. Nevertheless my main concern is working with tables since they are crucial for a project I'm working on. Thanks again!

I assume, that iterating through all the cells of a column one by one and setting a background color would be possible too, if that helps in researching this issue.

Dev-iL commented 6 years ago

Hmm, I suppose this is because the table demo was developed on a later MATLAB version, which changed some aspects of uifigures. Is updating the MATLAB version a possibility for you?

The way I usually go about "uncovering" the right way to modify elements is to dump the HTML code, and then explore it in a browser. You can do it using the following code:

uiFig = uifigure();
mlapptools.setTimeout(uiFig,15);
tbl = uitable(uiFig);
H = mlapptools.getHTML(uiFig);
dataTag = char(struct(struct(tbl).Controller).ProxyView.PeerNode.getId);

Then copy the contents of H into an .html file, open it in a browser, inspect the elements and try to located one having a property like the contents of dataTag, as this is your baseline. From there you can usually find some route using parent/nth-child nodes to the element you actually want to modify.


In R2017b, the DOM node related to the uitable has a very strange structure:

<div class="mw_type_Table mw_type_TableBase mw_type_ListBase mw_type_DataGrid
 mw_type_Component hideRowHeaders hideColumnHeaders showCellBorders hideVerticalScroll
 hideHorizontalScroll mgg arrayTable gbtTable" 
 id="mgg_b76f1aa0" widgetid="mgg_b76f1aa0" data-tag="datatools.variableeditor.views.table">

So now the question is how to get a widgetid starting with mgg_ from the tbl object...? If we can figure this out, consider your problem solved.

In any case, I would advise against working with empty tables as this is needlessly complicated.

t2m4k1 commented 6 years ago

Since its an older group project I'm working on, I'm limited to using 2016b... It would be great if you could help me figure out a solution nevertheless. Thanks for your efforts and I'll continue to experiment with filled tables instead!

altmany commented 6 years ago

@t2m4k1 - since you're limited to R2016b where web-based (Add-Designer) uifigures are quite limited, I suggest that you consider using regular (java-based) figures instead, where uitables are much more powerful and customizable. See for example here, here and here.

Dev-iL commented 6 years ago

Small update - I took a long look at this yesterday and tried various ways to get the mgg_ handle mentioned above, unfortunately without success, but it got me thinking...

@t2m4k1 - before the tool can be updated, I first need to know the style of which element of the HTML should be modified, so that I can try to figure out which handle is required. If you want to help, please create a figure like so:

function H = issue15
uiFig = uifigure();
mlapptools.setTimeout(uiFig,15);
uitable(uiFig,'Data', magic(3));
mlapptools.waitForFigureReady(uiFig);
pause(3); % to be on the safe side
H = mlapptools.getHTML(uiFig); % should be about 24k characters long

then put the output in an html file, open it in a browser, and find the DOM node to which your style should ideally be applied.

I'm leaving this be for now due to a lack of ideas.

P.S. Don't forget that you can change the text and background color using documented features.

Dev-iL commented 6 years ago

@t2m4k1 I have just pushed a commit which is supposed to make it easy to apply styles to specific cells. Be advised that:

Using the code in the commit message,

% Create figure:
uiFig = uifigure('Position', [100 100 800 130]); mlapptools.setTimeout(uiFig,15);
hT(1) = uitable(uiFig,'Data', magic(3), 'Position', [020 020 300 80]);
hT(2) = uitable(uiFig,'Data', magic(4), 'Position', [350 010 400 100]);
% Get IDs:
ID1 = mlapptools.getTableCellID(hT(1), 1:3, 1:3 );        % select diagonal
ID2 = mlapptools.getTableCellID(hT(2), 1:4, 3*ones(1,4)); % select column
pause(5); % Wait a bit to ensure tables are ready.
% Apply styles:
hWW = mlapptools.getWebWindow(uiFig);
arrayfun(@(x)mlapptools.setStyle(hWW, 'background', 'red',    x), ID1);
arrayfun(@(x)mlapptools.setStyle(hWW, 'background', 'yellow', x), ID2);

I could get: image

I hope this could prove useful to you.

altmany commented 6 years ago

@Dev-iL - I think that it should be simple enough to modify mlapptools.setStyle (and the other sibling methods) to accept an array of IDs, i.e. to implement arrayfun() inside mlapptools.setStyle rather than force the users to do it (or to use a for-loop). The usage would then be even more intuitive, i.e. :

mlapptools.setStyle(hWW, 'background', 'red',    ID1);
mlapptools.setStyle(hWW, 'background', 'yellow', ID2);
Dev-iL commented 6 years ago

@altmany Thanks for the suggestion. I have incorporated it into the latest experimental commit (for now, only in setStyle, until I get some feedback). Essentially:

% Handle the case of a non-scalar ID_obj recursively:
if ~isscalar(ID_obj)
  arrayfun(@(x)mlapptools.setStyle(win, styleAttr, styleValue, x), ID_obj);
else   
  ... Do what we did previously