Smooth transition (optical effect) between uitabpanels in Matlab - user-interface

I have designed a group of three uitabpanels objects.
htab = uitabgroup('v0');
th1 = uitab('v0',htab,'title','Panel 1','ButtonDownFcn',...
#th1_ButtonDownFcn);
th2 = uitab('v0',htab,'title','Panel 2','ButtonDownFcn',...
#th2_ButtonDownFcn);
th3 = uitab('v0',htab,'title','Panel 3','ButtonDownFcn',...
#th3_ButtonDownFcn);
My intention is having a smooth transition between them when I change the selected uipanel through the mouse click. I pretend to achieve it changing the 'Visible' property of the elements contained inside them using the ButtonDownFcn function ( I got this idea based on the description section of this page).
set(handles.th2,'Visible','off');
set(handles.th3,'Visible','off');
...
function th1_ButtonDownFcn(hObject, eventdata)
handles = guidata(fh);
set(handles.th1,'Visible','on');
set(handles.th2,'Visible','off');
set(handles.th3,'Visible','off');
guidata(fh,handles);
end
function th2_ButtonDownFcn(hObject, eventdata)
handles = guidata(fh);
set(handles.th1,'Visible','off');
set(handles.th2,'Visible','on');
set(handles.th3,'Visible','off');
guidata(fh,handles);
end
function th3_ButtonDownFcn(hObject, eventdata)
handles = guidata(fh);
set(handles.th1,'Visible','off');
set(handles.th2,'Visible','off');
set(handles.th3,'Visible','on');
guidata(fh,handles);
end
where
fh: handle of the figure where they are contained the uitabpanels.
handles.th1, handles.th2, handles.th3: handles of the elements contained into each uitabpanel respectively.
However, it has not worked (I click on each one of uitabpanel's tabs and the visibility of them do not change) and I do not understand why.

In conclusion, the ButtonDownFcn and SelectionChangeFcn functions of an UITAB are already active when you click in the tabĀ“s label. So it is not possible to achieve the desired target (smooth optical transition) because the obtained result (modifying the mentioned functions) is the same that doing nothing.

Related

Create PySimpleGUI list with a key

I wish to have a list of text items in a PySimpleGUI that I can update later. That is, I want to have a key for the list. This might be vertical or horizontal, and I do not know how many items there will be.
I end up with different use cases, but the current one is to make a single line of text items with different colors. Other times, I need to write and update a customized table, just different enough that the table widget does not work.
Conceptually, I want to do something like this:
layout = [ [sg.T('Titles and Things')], sg.ListThing(key='-data-', [[]]) ]
so that I can:
window['-data-'].update(values=[ [sg.T(v, color=c)] for (v,c) in my_data ])
Another, invalid syntax, way of saying what I want is to use [key="-data-", sg.T('Item1'), sg.T('Item2')].
Is this possible?
You can update individual layout elements but you cannot dynamically change the layout itself.
It is possible to create 2 or more elements, whereby only one of them is visible, and switch them later as needed. Or you can close and re-create the window with another layout. Or combine both approaches.
An example of switching layouts:
def change_layout():
left_col_1 = sg.Column([[sg.Text(f'Text {i}') for i in range(4)]], visible=True, key='col_1')
left_col_2 = sg.Column([[sg.Text(f'Text {i}')] for i in range(6)], visible=False, key='col_2')
visible_1 = True
layout = [[sg.Column([[left_col_1, left_col_2]]), sg.Button('Change layout', key='change')]]
window = sg.Window('window', layout=layout, finalize=True)
while True:
event, values = window.read()
print(event)
print(values)
print(visible_1)
if event in ('Exit', sg.WIN_CLOSED):
break
if event == 'change':
window['col_1'].update(visible=not visible_1)
window['col_2'].update(visible=visible_1)
visible_1 = not visible_1
Please notice that the alternative layouts for the left part (left_col_1, left_col_2) need to be enclosed in a container (column, frame) to keep their position in the window in the moment they are invisible.

Codename One Transition Form Automatically Scrolls to Top

I have an app with lots of components that use slide transitions.
The components, ScaleImageButtons and -Labels are added to the form directly via a GridLayout. There are also timer events involved, to make the scenario more dynamic and appealing
The form is, of course, scrollable.
Now, every time I call the form and scroll it down, it automatically jumps back to the first item at the top of the form, once that becomes animated.
But the form should stay at the current scroll position, independent of the position of the animated item, being this visible or not.
How can can make the form keep the current scroll position, independent of the position of the currently animated item?
formApps.setFocusScrolling(false); // does not help
Here is the code:
(THIS CODE WAS EDITED TO REFLECT THE WORKING SOLUTION)
Form formApps = new Form(new GridLayout(6, 2));
ArrayList<String> listApps = classStrings.listApps;
for (int i = 0; i < listApps.size(); i++) {
Container container = new Container();
ScaleImageButton scaleImageButton = new ScaleImageButton(image);
SpanButton spanButton = new SpanButton(stringDescrip);
container.add(scaleImageButton);
UITimer uit00 = new UITimer(() -> {
UITimer uit01 = new UITimer(() -> {
container.replace(spanButton, scaleImageButton,
CommonTransitions.createCover(CommonTransitions.SLIDE_HORIZONTAL, true, slideInterval));
});
uit01.schedule(startInterval, false, formApps);
UITimer uit02 = new UITimer(() -> {
container.replace(scaleImageButton, spanButton,
CommonTransitions.createCover(CommonTransitions.SLIDE_HORIZONTAL, true, slideInterval));
});
uit02.schedule(repeatIntervalOne, false, formApps);
});
uit00.schedule(repeatIntervalOne, true, formApps);
});
form.setFocusScrolling(false);
form.add(container);
container.setScrollableY(true);
formApps.show();
You shouldn't use Timer here directly. That violates the EDT. You should either wrap the timer callback in callSerially or better yet just use a UITimer which is designed exactly with this purpose in mind.
6x2 is a relatively small grid so it's possible that a small movement is enough to send you to the top as elements get resized. The size of the grid is determined by the preferred size of all the elements within. If the scaleImageButton is much larger than spanButton once they are replaced the layout might "jump" and you will end up with something much smaller which feels like scrolling but is just a new layout due to smaller preferred size.
A workaround for this would be:
Component.setSameSize(scaleImageButton, spanButton);

How I make a pushbutton invisible in a GUI?

I want to play my wav on percussion background image area with my pushbutton, so i need my pushbutton invisible on my figure window.
My script:
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
[s,fs]=wavread('filename.wav');
sound(s,fs);
Thankyou..
To make your push button invisible when you click it, set visibleto off in the callback function
set(hObject, 'Visible', 'off')
To make it invisible from other parts/functions in your GUI, just replace hObject with the handle of your push button.
Update:
You could make a clickable image and play different sounds for different click positions. Use the callback 'ButtonDownFcn' to trigger at a click event in the image. You can the retrive the position of the click by using the axes property 'CurrentPoint'. This return as 2x3 matrix with x-y-z projected coordinates. But as you are using a 2D plot you could simply pick the first 2 values, read more here.
Then use the x/y coordinates to find out what in the image that the user clicked on and play the sound for that.
A simple example:
% Draw an image
figure()
imHandle = image(imread(figPath));
% Set callback function (target function could have any name)
set(imHandle,'ButtonDownFcn', #ImgClickCB);
And the callback function (displays the x and y coord.)
function ImgClickCB(hObject, ~)
clickPoint = get( get(hObject,'Parent'), 'CurrentPoint');
fprintf('Clicked at x: %0.f y: %0.f \n', clickPoint(1,1), clickPoint(1,2));
The following example hides, and shows a pushbutton.
I created a sample, without using guide.
You can copy and paste the code into Matlab m file for execution.
Creating GUI without guide tool, better suit Stack Overflow site, because there is no need to attach a fig file.
You better use guide tool, because creating a GUI without it is complicated.
The following code sample hide (and show) pushbutton:
%TestNoGuideHideButton.m
%Create GUI with two buttons, without using GUIDE.
function TestNoGuideHideButton()
%Create figure.
h.fig = figure('position', [800 400 260 80]);
%Add button, with callback function Button1
h.buttonOne = uicontrol('style', 'pushbutton',...
'position',[10 20 100 40], ...
'string' , 'Button1', ...
'callback', {#Button1});
%Add button, with callback function hideButton
h.buttonTwo = uicontrol('style', 'pushbutton', ...
'position',[150 20 100 40], ...
'string' , 'Hide Button1', ...
'callback', {#hideButton});
function Button1(hObject, eventdata)
%Modify color of Button1 to random color.
set(h.buttonOne, 'BackgroundColor', rand(1, 3));
end
function hideButton(hObject, eventdata)
is_visible = isequal(get(h.buttonOne, 'Visible'), 'on');
if (is_visible)
%Hide buttonOne if Visible.
set(h.buttonOne, 'Visible', 'off');
set(h.buttonTwo, 'string', 'Show Button1'); %Replace string.
else
%Restore buttonOne if hidden.
set(h.buttonOne, 'Visible', 'on');
set(h.buttonTwo, 'string', 'Hide Button1'); %Replace string.
end
end
end
For the problem you described above, you obviously can't add a button for showing and hiding the other button.
You can restore the button when playing finishes.
You can also add a callback function for the background figure (look for WindowButtonDownFcn in guide).
Pressing anywhere on the figure, triggers the callback, were you can restore the hidden button.
You might want to have a look at this blog entry where I discussed how to manipulate the CData property of uicontrols.
I've added some code below to show a simple example:
f = figure(); % create a figure with an axes on it
pb = uicontrol('Style','checkbox', 'Units','pixels', 'Position',[10 10 300 200], ...
'Callback',#(a,b)msgbox('play clown!'));
% read some data
data = load ( 'clown' );
% extract out the image
img = data.X;
% convert image to RGB for displaying on checkbox
img = ind2rgb(img,colormap(f));
% Set the cdata property of the checkbox to be the image of interest
set(pb, 'CData', img )
The above code creates a figure with an image of a clown which you can click on (this could be your drum). The "button" stays there the whole time you don't need to make it invisible
Note: I use a checkbox instead of a button -> because sometimes a button can have a "border" when its in focus which can detract from the image whereas a checkbox doesn't.
I've copied the image produced below (after I clicked on the button):

Modifing Selection Ckeditor

At the moment i have the following problem, i'm applying span tags with the applyStyle Method from CKEDITOR 4.x. But when a span is partial selected and i execute the applyStyle method a new span will be made with the selection, but the other half of the selected span isn't restored and loses his span.
First Question: Is it possible to prevent partial selection of a certain element?
IF NOT My Second Question: Is it possible to extend the Selection only on one side, the side where the span(With a certain class or attribute) is partial selected. So that it will be fully selected for processing.
A Example:
This is 'my text <span class"testClass">, This' is </span> Other Text
And now we want a solution to create:
This is <span class"testClass2"> my text, This</span> <span class"testClass"> is </span> Other Text
Please take notice of the following:
The hard part in this is to maintain the html structure. when half of the selection is in an other block level element, it may not brake! That is the reason that i started using the applyStyle method.
First Question: Is it possible to prevent partial selection of a certain element?
Hmm... You can check placeholder plugin's sample - it uses non-editable inline elements to create those placeholders which at least on Chrome cannot be partially selected. Though, I think it's not a satisfying solution for you :)
Another possible solution is using editor#selectionChange event on which you can check if one of selection ends is located inside that element and if yes, set it before or after that element. It'd look like (I haven't tested this code, it's just a proto):
editor.on( 'selectionChange', function( evt ) {
var sel = evt.data.selection,
range = sel.getRanges()[ 0 ];
if ( protectedElement.contains( range.startContainer ) || protectedElement.equals( range.startContainer ) )
range.setStartAt( protectedElement, CKEDITOR.POSITION_BEFORE_START );
if ( protectedElement.contains( range.endContainer ) || protectedElement.equals( range.endContainer ) )
range.setEndAt( protectedElement, CKEDITOR.POSITION_AFTER_END );
sel.selectRanges( [ range ] );
} );
Although, this kind of solutions are always dangerous and can cause many unpredictable situations. But it may be worth checking it.
Back to the root of your problem - I understand that you want to create styles which work on the same level - i.e. only one can be applied in one place. This isn't possible using styling system. You would have to prepare range before applying style. The code would be similar to the selectionChange listener - you check if ends are anchored in style element, if yes you need to move range's ends out of it. The only question is how to exclude entire element from range in this situation:
<p>foo[bar<span class="st1">bom</span>bim]foo</p>
The result should be two ranges:
<p>foo[bar]<span class="st1">bom</span>[bim]foo</p>
Unfortunately current range's API does not include helpful method like range#exclude, therefore you need to implement yours. I would try doing this with walker. Iterate from range's start to end and remember all style elements. If you'll do this in both directions you'll gather also partially selected elements on both ends, so the first step I described will be unnecessary. When you'll have list of elements which you want to exclude from range, then you just need to create ranges at both ends and between these elements - this part should be easy. Element#getPosition will be helpful, but you'll need to check its code to understand how to use it because it isn't documented.
I have been looking and trying for hours. And chose to make an enlarge function myself to expand the selection. I made my own enlarge/expand function as i wanted to have more control which the enlarge of CKEDITOR doesn't provide.
The code:
//Vars
var firstNode = range.startContainer.getParent();
var lastNode = range.endContainer.getParent();
//Make end Get full if is tcElement
if(lastNode.type === CKEDITOR.NODE_ELEMENT && lastNode.getName() === "myElement")
{
range.setEndAfter(lastNode);
}
//Make end Get full if is tcElement
if(firstNode.type === CKEDITOR.NODE_ELEMENT && firstNode.getName() === "myElement")
{
range.setStartBefore(firstNode);
}
range.select();
Other nice piece of code, which isn't very hard but can be useful for other people.
This code i used to split the code in 2 or 3 parts.. where part 1 and 3 are the partial selection if existed.
Spliting to multiple ranges
//Vars
var newRanges = [];
var allWithinRangeParent = range.getCommonAncestor().getChildren();
var firstNode = range.startContainer;
var lastNode = range.endContainer;
var firstNodeStart = range.startOffset;
var lastNodeEnd = range.endOffset;
//TODO make if to check if this needs to be made.
//make end partial
var newEndRange = new CKEDITOR.dom.range( editor.document );
newEndRange.selectNodeContents( lastNode );
newEndRange.endOffset = lastNodeEnd;
newRanges.push(newEndRange);
//TODO make if to check if this needs to be made.
//Make start partial
var newStartRange = new CKEDITOR.dom.range( editor.document );
newStartRange.selectNodeContents( firstNode );
newStartRange.startOffset = firstNodeStart;
newRanges.push(newStartRange);
//Make center selection.
var tempRange = new CKEDITOR.dom.range( editor.document );
tempRange.setStartBefore(firstNode.getParent().getNext());
tempRange.setEndAfter(lastNode.getParent().getPrevious());
newRanges.push(tempRange);
selection.selectRanges(newRanges);

Want to move a slider and all the others update in Matlab?

I have GUI in Matlab that I have made using the Programmatic approach. It has 6 sliders and I want to be able to move one of them and have the others update as if i clicked them again but to stay in the same place. I am guessing I will need to use the set() function. Is there some function to do this in matlab already? I have been looking around. Any suggestions or something to point me in the right direction?
If you are using guide, you can access the other sliders from the handles variable that is available in each callback.
Set the Value property for them.
function Slider1_CallBack(hObj,evt,handles)
set(handles.Slider1,'Value',10);
set(handles.Slider2,'Value',10);
% etc..
end
In case you are using it programmaticaly, you can store the handles manually.
function main
handles.Figure1 = figure(..);
handles.Slider1 = uicontrol(...);
handles.Slider2 = uicontrol(...);
guidata(handles.Figure1,handles);
end
And your slider callback should be:
function Slider1_CallBack(hObj,evt)
handles = guidata(hObj);
set(handles.Slider1,'Value',10);
set(handles.Slider2,'Value',10);
% etc..
end
Edit A good practice in writing UI is separating the GUI logic from the actual data. You always change the data, and call updateGUI routine.
Therefore, you can write your program like this:
function main
handles.gui.Figure1 = figure(..);
handles.gui.Slider1 = uicontrol(...);
handles.gui.Slider2 = uicontrol(...);
handles.data.x = 1;
guidata(handles.Figure1,handles);
end
function UpdateGui(handles)
%Based on the data, update the GUI
set(handles.Slider1,'Value',handles.data.x);
set(handles.Slider2,'Value',handles.data.x+1);
end
And the callback should look like:
function Slider1_CallBack(hObj,evt)
handles = guidata(hObj);
handles.data.x = handles.data.x + 1;
UpdateGui(handles);
guidata(hObj,handles);
% etc..
end

Resources