How do I make the matlab-uitable CellSelectionCallback respond to multiple consecutive clicks in the same cell? - matlab

--UPDATE--
I discovered that the uitable does not register a 'second click' when t.ColumnEditable = true. When this is true, MATLAB waits until you personally deselect the cell to begin registering new clicks. Hence, that entire time it expects that new clicks are edits to the cell. Turn t.ColumnEditable to false and consecutive clicks register as new actions.
--
The CellSelectionCallback only seems to register clicks in new cells. For example, the following only displays 'src' and 'event' during the first click to any particular cell:
close all;
f = figure('Position',[50,62,1340,326],'Units','pixels'); % set figures so they're stacked
f.Name = 'Debugging table';
t = uitable(f,'Units','normalized','Position',[.05,.05,.9,.9]);
t.CellSelectionCallback = #cellSelected;
t.ColumnName = {};
t.RowName = {};
t.Data = magic(10);
t.FontSize = 10;
t.FontName = 'AppleGothic';
function [src,event] = cellSelected(src,event)
src
event
end
Can anyone provide a method that branches off of something like this that would allow the code inside 'cellSelected' to run on more than one consecutive click to a single cell in the active uitable? Thanks in advance.

--UPDATE--
I discovered that the uitable does not register a 'second click' when t.ColumnEditable = true. When this is true, MATLAB waits until you personally deselect the cell to begin registering new clicks. Hence, that entire time it expects that new clicks are edits to the cell. Turn t.ColumnEditable to false and consecutive clicks register as new actions that independently trigger the cellSelected callback function.
--

Related

Matlab: GUI radio button SelectionChangedFn Callback

I'm trying to figure out how to make a GUI with radio buttons that will enable/disable options based on radio button selections. Here's an example of one way I have tried:
fig = uifigure('NumberTitle','off','Name','Option Selection','Position',[750,300,460,520]);
panel1 = uipanel(fig,'Title','Options','Position',[140,80,200,280]);
bg = uibuttongroup(fig,'Position',[140 290 200 51],'SelectionChangedFcn',#bselection);
rb1 = uiradiobutton(bg,'Position',[5 30 100 20],'FontWeight','bold');rb1.Text = 'Option 1';
rb2 = uiradiobutton(bg,'Position',[5 10 100 20],'FontWeight','bold');rb2.Text = 'Option 2';
Opt1_label = uilabel(panel1,'text','Option 1','Position',[5 180 100 20],'FontWeight','bold');
Opt1_field = uieditfield(panel1,'text','Position',[5 160 100 20]);
Opt2_label = uilabel(panel1,'text','Option 2','Position',[5 60 250 20],'FontWeight','bold');
Opt2_field = uitextarea(panel1,'Position',[5 15 190 45]);
function bselection(bg,Opt1_label,Opt1_field,Opt2_label,Opt2_field)
if bg.Buttons(1).Value == 1
Opt1_label.Enable=1;
Opt1_field.Enable=1;
Opt2_label.Enable=0;
Opt2_field.Enable=0;
elseif bg.Buttons(2).Value == 1
Opt1_label.Enable=0;
Opt1_field.Enable=0;
Opt2_label.Enable=1;
Opt2_field.Enable=1;
end
end
The enable/disable if statement works standalone, but I cannot figure out how to get it to work as a callback. Option 2 is not disabled even though option 1 is selected first by default, and if I select another radio button, either nothing changes or I will get an error saying the Enable handle isn't found.
Any ideas are much appreciated
Thanks in advance!
You have configured your function bgselection() to be a callback function for a UI element. Callback functions have two specific rules for the input arguments:
The first argument must be the handle of the object that called the function, and the second must be "eventData" for the callback event. So in your function, the argument Opt1_label is being treated as a eventData variable. Since it does not have the information expected in that variable, there is an error. So to follow this rule, change your function definition to:
function bselection(bg,eventData,Opt1_label,Opt1_field,Opt2_label,Opt2_field)
The second rule is that if you want to have more than the required two input arguments, you need to list them in a cell array when the function is assigned to the object. So in your case, define the uibuttongroup like this:
bg = uibuttongroup(fig,'Position',[140 290 200 51],'SelectionChangedFcn',{#bselection,Opt1_label,Opt1_field,Opt2_label,Opt2_field});
You will have to move the definitions of Opt1_, Opt2_ etc before the bg statement, so that they exist and can be included in the cell array.
You can see the documentation for this here. There are a couple other options for passing arguments, but these are the most common methods.
Also, the eventData has some useful information, such as the label of the button that is selected. Try adding disp(eventData) to the function to see what is included there.

Access VBA to Change an Image in a Continuous Form

I am trying to create a receipt form where people will confirm if they've received the full quantity of an order. As part of this, I want the following to happen:
If they received the full quantity, a green check mark appears
If they received a partial quantity, an orange triangle appears
If they received no items, a red x appears
To accomplish this, I'm using a continuous form with 3 image files for each situation. I'm using the code below to change the image when the quantity is changed. The problem is, when the quantity is change on 1 line, the symbol changes for all lines. I'll post pictures as well.
Any thoughts on how I can fix this?
I'm open to other methods of accomplishing this idea too.
Private Sub FinalQTY_AfterUpdate()
If IsNull(Me.FinalQty) Then
MsgBox "You must enter a quantity for this item"
Me.FinalQty.SetFocus
Exit Sub
Else
LValue = Me.[FinalQty]
If IsNumeric(LValue) = 0 Then
Me.FinalQty = ""
MsgBox "Qty must be a numeric value"
Me.QTY.SetFocus
Exit Sub
End If
End If
Me.FinalTotalPrice = Me.FinalPrice * Me.FinalQty
If Me.FinalQty = 0 Then
Me.Yes.Visible = False
Me.Change.Visible = False
Me.No.Visible = True
End If
If Me.FinalQty < Me.QTY Then
Me.Yes.Visible = False
Me.Change.Visible = True
Me.No.Visible = False
End If
If Me.FinalQty = Me.QTY Then
Me.Yes.Visible = True
Me.Change.Visible = False
Me.No.Visible = False
End If
End Sub
This is before I adjust the quantity:
This is after I adjust the qty of only the second line:
Since the formatting of each record displayed by a continuous form is inherited from the form design template, any changes to the template will be automatically applied to all records displayed by the form, aside from Conditional Formatting rules in effect or the handful of properties which may changed via the OnPaint event of the Detail section.
One possible alternative might be to add a new field to your table with a data type of OLE Object and populate the value on the AfterUpdate event using the AppendChunk method, sourcing image data from a separate table containing three records corresponding to your green tick, orange triangle, and red cross images.

Table cells to be edited only on double click

The table cell is edit with a simple click, I want it to be edit only on double click. Simple click will select the cell.
I'm use this property of uitable:
set(hTable, 'Data',data,...
'ColumnEditable', edit,...
First you need to set the cell editabiliy to false by default:
set(hTable,'ColumnEditable', [false false ...]); %accordingly your number of columns
and introduce a CellSelectionCallback:
set(hTable,'CellSelectionCallback',#cellSelect);
which calls the following function within the same script
function cellSelect(src,evt)
getstate = get(src,'ColumnEditable'); %gets status of editability
index = evt.Indices; %index of clicked cell
state = [false false ...]; %set all cells to default: not editable
state(index) = ~getstate(index); %except the clicked one, was it
%already false before set it true
set(src,'ColumnEditable', state) %pass property to table
end
and also a CellEditCallback:
set(hTable,'CellEditCallback',#cellEdit);
calling
function cellEdit(src,~)
state = [false false ...];
set(src,'ColumnEditable', state)
end
minimal example
function minimalTable
h = figure('Position',[600 400 402 100],'numbertitle','off','MenuBar','none');
defaultData = {'insert number...' , 'insert number...'};
uitable(h,'Units','normalized','Position',[0 0 1 1],...
'Data', defaultData,...
'ColumnName', [],'RowName',[],...
'ColumnWidth', {200 200},...
'ColumnEditable', [false false],...
'ColumnFormat', {'numeric' , 'numeric'},...
'CellSelectionCallback',#cellSelect);
end
function cellSelect(src,evt)
getstate = get(src,'ColumnEditable');
index = evt.Indices;
state = [false false];
state(index) = ~getstate(index);
set(src,'ColumnEditable', state)
end
function cellEdit(src,~)
state = [false false];
set(src,'ColumnEditable', state)
end
As you figured out this is not always working. Because you have the same issues like I had before with popup menus. It's exactly the same problem: ColumnEditable is just a row vector and not a matrix. I had to deal with the ColumnFormat property, which is also just a row vector. If the double click feature is really important to you, you can consult the following two answers:
Is it possible to prevent an uitable popup menu from popping up? Or: How to get a callback by clicking a cell, returning the row & column index?
How to deselect cells in uitable / how to disable cell selection highlighting?
The threads basically suggest to create a unique uitable for every single row, so that every single row has a unique ColumnEditable property. That's the only solution so far.
I'm afraid there is no simple solution. I can't offer you further help, except the complicated workarounds of the other answers. Or just use the simple one above and live with the little drawbacks.
Although this thread is old but in my opinion still valuable to some users.
I have tested the following with R2010b 32bit.
I have achieved editing only on double click simply by setting
set(hTable,'CellSelectionCallback',#tableCellSelectCB,'ColumnEditable',true)
and defining its function the following
function tableCellSelectCB(~,~)
try
h.jtable.getCellEditor().stopCellEditing();
catch
end
end
where h.jtable refers to the underlying java object of your uitable.
This way, I can select even single and multiple cells, without going into edit mode. On a double click on a single cells lets me edit its contents.
Extension to have individual editable rows
I wanted to have checkboxes in the top row and non-editable (not directly at least) data in the rest of the table. You can easily modify the above:
function tableCellSelectCB(~,evd)
if evd.Indices(1) > 1
try
h.jtable.getCellEditor().stopCellEditing();
catch
end
end
end

MS Access - Close form without save design changes, acSaveNo doesnt work

I have a Front End/Back End app in MS Access and I'm having some problems with performance when I close forms.
These forms are always saving before close because in Form_Open I hide some columns and edit the caption. Then, when I close the form, it saves the hidden columns and wastes much time!
I have already done a lot of settings modifications in Access for optimize for FE/BE. But I'm still have problems with forms that save before close. On save event it really wastes a lot of time. With the hide/edit columns routine it takes 20s to save. Without the routine it takes 1s or less, but my data is not saved.
How could I hide/edit these columns without the need to save the form afterwards? Or how could I close the form without saving structure changes?
Unfortunately Access doesn't have a BeforeClose event, and in a Close or Unload event it saves before going to this sub, so I can't cancel it to close later in code.
Hide Code:
'show all columns
For i = 1 To 8
Form_Y_SubF_LP.Controls("Item_00" & i).ColumnHidden = False
Form_Y_SubF_LP.Controls("Quantity_00" & i).ColumnHidden = False
Form_Y_SubF_LP.Controls("DistributionEQ_00" & i).ColumnHidden = False
Next
'Hide unnecessary columns
For i = 8 To ProtQuant + 1 Step -1
Form_Y_SubF_LP.Controls("Item_00" & i).ColumnHidden = True
Form_Y_SubF_LP.Controls("Quantity_00" & i).ColumnHidden = True
Form_Y_SubF_LP.Controls("DistributionEQ_00" & i).ColumnHidden = True
Next
'Change the caption of columns to the real name of each prototype
prot = DLookup("[Prototype]", "Y_Configurações", "[Program]= '" & ProgramName & "'")
For i = 0 To UBound(Split(prot, ";"), 1)
Form_Y_SubF_LP.Controls("Item_00" & i).Properties("Caption") = "Item_" & Split(prot, ";")(i)
Form_Y_SubF_LP.Controls("Quantity_00" & i).Properties("Caption") = "Quantity_" & Split(prot, ";")(i)
Form_Y_SubF_LP.Controls("DistributionEQ_00" & i).Properties("Caption") = "DistributionEQ_" & Split(prot, ";")(i)
Next
A simple solution is to set Close Button = No on the form's property sheet, then add a command button, cmdCloseMe, with this for its On Click event:
Private Sub cmdCloseMe_Click()
DoCmd.Close acForm, Me.Name, acSaveNo
End Sub
If you need your form displayed in Datasheet View, you would need to embed it in a subform control of another form and add the cmdCloseMe button to that form.

Setting up some properties for a combobox (scroll, edit, jump)

There are 3 properties that I want to set for some VBA form comboboxes and I don't know if it's possible.
I don't want to let the combobox editable. Right now if the user types something in it that it submits the form it will send that value... I want to let him choose only from the values I added in the Combobox.
I want to make the list of items in the combobox scroll-able. Right now I'm able to scroll through the list if I use the scroll-bar but I don't know why I can't scroll with the mouse scroll.
And I want to jump to some item if I start typing. Let's say I have the months of the year in one combobox... if I start to type mar I want it to jump to march. I know that for the html forms this properties is by default but I don't know about VBA forms...
Thanks a lot
Of the behaviours you want, some are possible with settings on the Combo, others you will need to code
List of Months: Put a list of entries on a (hidden) sheet and name the range. Set .RowSource to that range
Match as you type: Set properties .MatchEntry = fmMatchEntryComplete and .MatchRequired = True
Reject non list entries: A Combo with these settings will allow you to type an invalid entry, but will reject it with an error message popup when you commit. If you want to silently reject invalid data as you type, you will need to code it.
If you want the selected value returned to a sheet, set .ControlSource to a cell address (preferable a named range)
By "...scroll with the mouse scroll..." I assume you mean the mouse wheel. Unfortunatley Forms don't support mouse wheel scroll. You will have to code it yourself. There is a Microsoft patch for this at here (not tried it myself yet)
Sample code to silently reject invalid entries
Private Sub cmbMonth_Change()
Static idx As Long
Dim Match As Boolean
Dim i As Long
If cmbMonth.Value = "" Then Exit Sub
If idx = 0 Then idx = 1
i = idx
Match = False
For i = 0 To cmbMonth.ListCount
If cmbMonth.List((i + idx - 1) Mod cmbMonth.ListCount) Like cmbMonth.Value & "*" Then
cmbMonth.ListIndex = (i + idx - 1) Mod cmbMonth.ListCount
Match = True
Exit For
End If
Next
If Not Match Then
cmbMonth.Value = Left(cmbMonth.Value, Len(cmbMonth.Value) - 1)
End If
End Sub
Set the propertie MatchEntry of combobox to 1 (fmMatchEntryComplete) and MatchRequired to true for example
combobox1.MatchEntry=1
combobox1.MatchRequired=True
[]'s