There is data validation in my MS Word user form which returns the focus to the textbox where the user entered something incorrect. Now I am trying to accommodate the user's change of mind: instead of correcting the entry, I want him to be able to exit the form (click the Exit command button), in which case the entry would be discarded. I suppose that a solution would start with not using the text box's exit event. I little help from someone who knows the answer would save me a lot of testing time, perhaps to find out that I can't do it.
Does anyone know?
I understand that you are handling the Exit event of the Textbox, setting the Cancel output parameter if the data is not valid.
There's a tricky but simple solution that permits to keep that working and still have an Exit button. It permits to activate the handler of the Exit button without requiring the focus to leave the Textbox. This way you can unload the Form safely in this handler.
Try this it works pretty smoothly:
1- Set the property TakeFocusOnClick of the Exit command button to False. You can do that at design time in the property-sheet, or at run-time i.e. at UserForm_Activate
2- just unload the form when the Exit button is clicked:
Private Sub ExitButton_Click()
Unload Me
End Sub
#A.S.H provided the key to the solution below. His point is that it is possible to call another event procedure while Cancel is active in the Exit procedure of a control. That other procedure can be used to rectify the condition in the first control which is triggering the Cancel, thereby enabling an orderly exit. The all-enabling condition is that the control on whose click event the rectifying procedure is to run must not take the focus when clicked (meaning it can run without triggering an exit from the control stuck on Cancel). I have added code to the exit procedure to set CmdExit.TakeFocusOnClick = False when a Cancel condition arises there. Now, ...
Private Sub CmdExit_Click()
' 12 May 2017
' if CmdExit can't take the focus it can't be the ActiveControl
If Not ActiveControl Is CmdExit Then
Select Case ActiveControl.Name
Case "Cbx107"
Cbx107.Value = ""
Case "Tbx53"
Tbx53.Value = "0"
End Select
With CmdExit
If Not .TakeFocusOnClick Then
.TakeFocusOnClick = True
.SetFocus
End If
End With
End If
' now CmdExit is the ActiveControl
MsgMe "Cmd Exit: ActiveControl = " & ActiveControl.Name
Me.Hide
End Sub
I have written functions that access off-sheet data that is prone to changing regularly. Pressing Ctrl+Shift+F9 refreshes these cells, while F9 alone does not. Is there a way to automate refreshing this data - say, once a minute?
Running libreoffice 4.4.3.2
Ok you can use a link to a value in another sheet if you like.
To create a name range insert->names->define
Sub recalc_timer
document = ThisComponent.CurrentController.Frame
switch_on = ThisComponent.NamedRanges("switched_on").ReferredCells.getCellByPosition(0,0)
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem value must be more than 0 to hold while condition
while switch_on.getValue()>0
dispatcher.executeDispatch(document, ".uno:CalculateHard", "", 0, Array())
rem wait time in milliseconds
wait 3000
wend
End Sub
*proviso
Important: Some functions may not be updated. Please test https://help.libreoffice.org/Calc/Recalculate
I have designed my form in 1280*1024 resulotion. They lookvery nice on my Monitor, but If I see on another Monitors, they look very chaotic . Is there a way that I solve this problem?
It's not so easy. This is where MVC comes in very handy and you can distinguish between different components. You can have different views for different devices. Unfortunately VBA does not support that and you would have to implement your own framework to handle different screen resolutions.
The easiest way to avoid having to re-implement the design of your userform is to actually DESIGN it in your head before writing a single line of code. Think of the different resolutions(devices) your software is going to support, what the language you are using is supporting and what are your choices. Generally, think it over. In VBA I normally just go for the default size to avoid the headache of fitting someone's else screen.
You would have to redesign the entire UserForm. Not visually, but programmatically set both width, and height of the userform and make controls dependable on the current resolution. I do not recommend doing it this way but still this could be a solution.
You can achieve that by accessing the current resolution and modifying your Userform_Initialize() event.
So example, if the current resolution is 1024x768, you set the width and height to currentWidth-100px and currentHeight-100px.
If you open a new workbook and create an empty userform. Go to its code behind and add
Private Sub UserForm_Initialize()
Me.Width = GetCurrent(0) - 600
Me.Height = GetCurrent(1) - 800
End Sub
Then insert a module and add
Private Declare Function GetSystemMetrics Lib "user32.dll" (ByVal nIndex As Long) As Long
Sub A()
UserForm1.Show
Unload UserForm1
End Sub
Function GetCurrent(x As Long) As Long
GetCurrent = GetSystemMetrics(x)
End Function
This will display a different size userform depending on the current resolution.
you can (but I wouldn't recommend it) use that technique. Note: depending on how many controls you have this may be the best approach but if you have lots of controls on the userform I would look for an alternative.
Alternatively, you can use the below code which checks the current screen resolution, warns the users and asks if the user wants to change his resolution.
The below code comes from here and the original author is DRJ
You stick the first part in the Workbook code behind
Option Explicit
Private Sub Workbook_Open()
Call VerifyScreenResolution
End Sub
and the below part in a module
Option Explicit
Private Declare Function GetSystemMetrics Lib "user32.dll" (ByVal nIndex As Long) As Long
Const SM_CXSCREEN = 0
Const SM_CYSCREEN = 1
Sub VerifyScreenResolution(Optional Dummy As Integer)
Dim x As Long
Dim y As Long
Dim MyMessage As String
Dim MyResponse As VbMsgBoxResult
x = GetSystemMetrics(SM_CXSCREEN)
y = GetSystemMetrics(SM_CYSCREEN)
If x = 1024 And y = 768 Then
Else
MyMessage = "Your current screen resolution is " & x & " X " & y & vbCrLf & "This program " & _
"was designed to run with a screen resolution of 1024 X 768 and may not function properly " & _
"with your current settings." & vbCrLf & "Would you like to change your screen resolution?"
MyResponse = MsgBox(MyMessage, vbExclamation + vbYesNo, "Screen Resolution")
End If
If MyResponse = vbYes Then
Call Shell("rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,3")
End If
End Sub
update.
your initialize event is here
My code is really too long to be posted here, even by little portions. So I will just ask for one or two things :
It appears to me that when modifying the 'Data' property of an uitable 'ht' :
set(ht, 'Data', something);
that the "cellSelectionCallback" routine is triggered (as the selection is very likely to have changed, indeed), but not immediatly after the dataset is modified.
Is this true ?
Is there any way to prevent such a behavoir ?
Thanks !
I have code using a uitable, e.g:
tbl = uitable('Parent', fh, 'CellSelectionCallback',{#cell_select_callback fh});
I did a quick experiment and when using set(tbl,'Data',my_data) the callback is triggered only if the set causes the selected cell(s) to change, and this happens immediately (as far as I can tell - I saw no appreciable delay).
To stop that happening you could just unset the CellSelectionCallback property, change the data, and then reset CellSelectionCallback.
I had the same issue. Was getting index out of bounds warnings. To get rid of those I used this in my CallSelectionCallback:
if ~isempty(eventdata.Indices)
// all the code
end
When the set command triggers the CallSelectionCallback the eventdata.Indices is empty.
A similar possibility to Sebastien's answer is to put this in your cellselectioncallback function:
function output = mycellselection(source,event)
if isempty(event.Indixes)
output = [];
return
end
% rest of your code for cell selection
end
If you don't have any output needed, you can just remove it. I just put it in there to remind you that you have to assign a value to any outputs.
I'm trying to design a GUI in SciLab that updates it's properties depending on a checkmark. For example: A checkbox might enable and change the backrounds of several text boxes during a callback; or a pushbutton may require a certain number of checkboxes to be selected.
My problem is that I can't seem to develop a flow control statement for running instructions depending on the checkboxes state during a callback. My current UIControl element looks like this:
handles.chkS11En=uicontrol(f,'unit','normalized','BackgroundColor',[0.8,0.8,0.8],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[12],'FontUnits','points','FontWeight','normal','ForegroundColor',[0,0,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.02140625,0.791119360625398,0.0803125,0.0369667],'Relief','flat','SliderStep',[0.01,0.1],'String','S11','Style','checkbox','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','chkS11En','Callback','chkS11En_callback(handles)')
And my callback that runs when I check the checkbox is this:
cS11En = findobj('tag', 'chkS11En'); // checkbox option
tS11MagUpperBound = findobj('tag', 'txtS11MagUpperBound'); //edit box that is controlled
mprintf("%d\n",cS11En.Value);
if cS11En.Value == [1] then
mprintf("Checked = on \n");
set(tS11MagUpperBound,'BackgroundColor',[1,1,1]);
set(tS11MagUpperBound,"Enable",'on');
set(cS11Save,"Enable",'on');
elseif cS11En.Value == [0] then
mprintf("Checked = off \n");
set(tS11MagUpperBound,'BackgroundColor',[0.8,0.8,0.8]);
set(tS11MagUpperBound,'Enable','off');
set(cS11Save,"Enable",'off');
end
The problem with this code seems to be that the second path (Value = 1) never seems to run, even when i continually toggle the checkbox. I get an output like so:
0
Checked = off
0
Checked = off
0
Checked = off
0
Checked = off
Is there something I'm doing wrong in order to reload checking the element? I want to be able to run both paths, however I can never seem to get a value of 1 from the checkbox element. Does anyone have a solution to this? Thanks!
IF anyone is wondering and finds this through the googles or something, this is how I fixed it:
It turns out that SciLab sometimes doesn't clear all UI variables when the form is closed and a script is running.
The solution is to add a few lines in the top of each of your program that clears all variables, closes all forms, and initializes your variables.
Basically, add this:
// /////////////
// Lemon Pledge
// /////////////
mprintf("\n!!!!!!!!!!!!!!!!!!!\nCLEARING ALL VARIABLES\n!!!!!!!!!!!!!!!!!!!\n")
xdel(winsid());
clear;
clearglobal;
Another less complex solution would be:
Using the same checkbox I left the last attribute in blank.
handles.chkS11En=uicontrol(f,'unit','normalized','BackgroundColor',[0.8,0.8,0.8],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[12],'FontUnits','points','FontWeight','normal','ForegroundColor',[0,0,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.02140625,0.791119360625398,0.0803125,0.0369667],'Relief','flat','SliderStep',[0.01,0.1],'String','S11','Style','checkbox','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','chkS11En','Callback','')
Then I make the callback
function chkS11En_callback(handles)
if handles.chkS11En.Value == [1] then
mprintf("Checked = on \n");
set(tS11MagUpperBound,'BackgroundColor',[1,1,1]);
set(tS11MagUpperBound,"Enable",'on');
set(cS11Save,"Enable",'on');
else
mprintf("Checked = off \n");
set(tS11MagUpperBound,'BackgroundColor',[0.8,0.8,0.8]);
set(tS11MagUpperBound,'Enable','off');
set(cS11Save,"Enable",'off');
end
And voilĂ , no need to clear your workspace.