How to make participant input appear on screen and be wrapped (Psychtoolbox) - matlab

I’m trying to create a rectangle box on screen in PTB wherein the participant can type text that is wrapped inside this box. So I would like to get the string input to be drawn on screen while typing in a rectangular box where the text input is wrapped to avoid it continuing outside the border of this box. I have been searching for a while now and haven’t found anything that works or anyone who did this before. I assume I might be overlooking something very simple.
I have tried using:
% Textbox
Screen('FrameRect',window, white, [300 300 1600 600],4);
message = [‘Your comments: ‘];
replySubj = Ask(window, message, white, black, 'GetChar',[300 225 1600 600]);
The response input is nicely drawn on screen while typing, but only on one line that is not wrapped when I reach the side of the box, or even my screen. Is their a way to wrap the text (e.g. by integrating WrapString.m) so it stays inside a specified rectangle on screen, and continues to a new line if the text is too long for one line?
Any help is very much appreciated.

Looking at the GetEchoString function, it does the following upon each character strike (to the best of my understanding of how the display is managed):
if it is Ctrl-C, Enter, or Return: exit;
if it is Backspace, issue command to re-draw the previous full string (prompt + user input) with the same colour as the background to erase it ; then remove the last character from the stored full string;
else append the character to the stored full string.
Then issue the command to draw the resulting updated full string in the specified colour, and finally update the screen following the previous commands, with the option dontclearset to 1 (incremental drawing, cf. Screen('Flip', windowPtr, 0, 1) call).
To add wrapping capabilities, we can thus modify GetEchoString as follows:
comment out the re-drawing commands when Backspace is hit, simply updating the stored string (see below);
add a call to WrapString on the updated string to wrap it;
used DrawFormattedText to issue command to display the wrapped string;
finally, call Screen('Flip', windowPtr) that is update the screen with dontclearset to 0 (default).
The relevant part of the function are now thus:
% adapted from PTB3 GetEchoString
while true
if useKbCheck
char = GetKbChar(varargin{:});
else
char = GetChar;
end
if isempty(char)
string = '';
break;
end
switch (abs(char))
case {13, 3, 10}
% ctrl-C, enter, or return
break;
case 8
% backspace
if ~isempty(string)
% Remove last character from string:
string = string(1:length(string)-1);
end
otherwise
string = [string, char];
end
output = [msg, ' ', string];
output=WrapString(output,maxNumChar);
DrawFormattedText(windowPtr,output,x,y,textColor,[],0,0,vLineSpacing);
Screen('Flip',windowPtr);
end
Where maxNumChar and vLineSpacing are to be defined depending on your needs.
This will take care of the horizontal wrapping of the text, while keeping the Backspace function working. Note however that you could still overflow vertically if the whole screen is filled.

Related

Matlab imline and text

Thank you for your answer. I should have been more clear. I need a text object for every line. Here's how far I got:
function calc_slope(handle,event)
on = get(handle,'State');
if strcmpi(on,'on') || strcmpi(on,'off'),
xy = imline;
addNewPositionCallback(xy,#(pos) disp_slope(pos));
end
function disp_slope(pos)
delete(findobj(gca,'Type','text'));
text((pos(1)+pos(2))/2,(pos(3)+pos(4))/2,['\DeltaY/\DeltaX = ',num2str((pos(4)-pos(3))/(pos(2)-pos(1))),...
' [\DeltaX = ',num2str(pos(2)-pos(1)),', \DeltaY = ',num2str((pos(4)-pos(3))),']']);
So, each toggle on the toggle button in the figure will throw in a draggable/resizable line and as I move the line the slope shows and updates, which looks pretty close to what I want. There are, however, two issues:
It deletes all other text boxes except for the very last (current)
text box of the line I'm moving around. I want to keep the last
value remained and shown for all existing lines.
If I delete a line by right-clicking on the line and choose
"delete", it deletes the line, but not the text box and rightfully
so. Now I have a text box that shows the slope of the line that
exists no longer in the figure. I want the text box to disappear
along with the line.
I'm having these problems and really not going anywhere because imline object behaves so much different than other typical objects and also the concept of the addNewPositionCallback is quite convoluted.
Please, somebody enlighten me on this.
Many thanks in advance,
Eric
Previous message:
I create a figure with toggle button on its toolbar by uitoggletool. The callback function for it is shown below:
function calc_slope(handle,event)
on = get(handle,'State');
if strcmpi(on,'on') || strcmpi(on,'off'),
xy=imline;
addNewPositionCallback(xy,#(xy)...
title(['\DeltaY/\DeltaX = ',num2str((xy(4)-xy(3))/(xy(2)-xy(1))),...
'[\DeltaX = ',num2str(xy(2)-xy(1)),...
',\DeltaY = ',num2str((xy(4)-xy(3))),']']));
end
As you can see, the example outputs the position data in the title of a figure using the 'title' command.
Is there a way to output this in a text box using the 'text' command?
I want to display the slope next to the line drawn.
Also, it will be great if the text box also gets deleted together with the associated line.
Please, help.
Thank you,
Eric

Error using whitespace in MATLAB GUI label

I am writing a gui now which contains a popupmenu. This pop up menu should show different names according to cell array called titles and looks like this:
handles.titles={'time','velocity','angular velocity'};
Next, when i click on the popupmenu, i want it to plot the column which connected to this title.
so if i clicked on the 2nd popupmenu option i would like to get graph of velocity vs time.
handles.Parameter_Menu=hObject;
axes(handles.low_axis);
guidata(hObject,handles)
x_axis=xlim([handles.top_axis]);
set(hObject,'string',handles.titles(1:size(handles.matrix.Data,2)));
channel = get(hObject,'Value');
title_channel=handles.titles{channel}
plot(handles.(handles.titles{1}),handles.(handles.titles{channel}));
text=['graph of ' handles.titles2{channel} ' vs ' handles.titles2{1}];
title(text,'fontsize',12)
set(gca,'fontsize',10)
grid on
The problem occurs when i try to use title{3} because it has a space between the words.
Of course i could write it like this angular_velocity but then when i use it in title of the graph i recieve the letter "v" small because of the _ before it.
Is there any option to make it work with space or option to use it with _ but to avoid its effect in the title?
To make the title in plot displays exactly _, you can insert \ before _ (similar to latex):
handles.titles={'time','velocity','angular\_velocity'};
UPDATE:
since you are not only using the titles{i} for plot, but also use it as a struct's fieldname in other commands, then there is no way to have space, because a struct's fieldname must satisfy some conditions: Valid field names begin with a letter, and can contain letters, digits, and underscores.
So, you must use titles{3} = 'angular_velocity' to make other operations work correctly, and set Interpreter property of the title to be none to make the plot's title display as typed (default is TeX Markup, that's why i used \_ for _ above):
title(handle_of_something, titles{3}, 'Interpreter','none')

Auto scroll to bottom with a textbox

I have an mdb file made by ms access. It got a form inside and inside the form there are one large textbox.
The intention of making this textbox is to show the progress of some work by adding messages inside the textbox:
txtStatus.value = txtStatus.value & "Doing something..." & vbCrLf
txtStatus.value = txtStatus.value & "Done." & vbCrLf
But the problem is, when the height of the text > height of the textbox, the new message is not displayed automatically. The textbox has a scroll bar, but I have to scroll it manually. I would like to auto scroll to the bottom whenever new text pop up.
I tried to add this code(copied from internet) in the On Change property, but the code failed, it does nothing:
Private Sub txtStatus_Change()
txtStatus.SelStart = Len(txt) - 1
End Sub
I wish there would be some simple and beautiful way to achieve this. I don't want to add some code which only work on some computers due to its dependence on the windows platform's kernel/etc.
You can do it via a call to a sub;
AppendText "Bla de bla bla."
.
.
sub AppendText(strText As String)
with txtStatus
.setfocus '//required
.value = .value & strText & vbNewLine
.selstart = len(.Value)
end with
end sub
There is a workaround to the design flaw mentioned by steve lewy in his comment on the original post. It is possible to have a text box that appears to do both of the following:
When the contents are too large for the box, and the box does not
have the focus, the box displays the last part of its contents,
rather than the first part of it.
When the box has the focus, it can scroll to any part of the text,
but it initially shows only the last part of the text, with the
cursor at the end of the text.
This is accomplished by actually having two identically-sized, overlaid text boxes, where one is visible only when the focus is elsewhere, while the other is visible only when it has the focus.
Here’s an example of how to do it in Access 2010.
Create a new Access database, and create a memo field named LongNote in its only table. Fill LongNote with some examples of long text. Create a form for editing that table.
Create a text box called BackBox with the desired size and font, too small to completely show a typical value of its data source, LongNote. (Instead of creating this box, you can rename the default text box created on the form.)
Make an exact copy of that box called FrontBox. Set the data source of FrontBox to be either the entire contents of BackBox or the last part of the contents, as shown below. The size of the last part, measured in characters, depends on the size of the box and its font, as well as on the kind of text to be displayed. It needs to be chosen by trial and error to reliably allow that many characters to be displayed in the box. For instance, here’s the formula for a box that can reasonably hold only 250 characters:
=iif(Len([BackBox])>=250,"... " & Right([BackBox],246),[BackBox])
If the whole value is too large to be shown, three dots precede the part that is shown to indicate that it’s incomplete.
Create another text box called OtherBox, just to have somewhere you can click besides the two boxes already mentioned, so neither of them has the focus. Also create a tiny (0.0097 x 0.0097) text box called FocusTrap, which is used to avoid selecting the entire contents of whatever text box gets the focus when the form is displayed (because text selected that way is hard to read).
Enter the following event-handling VBA code:
' Prevent all text boxes from being focused when a new record becomes
' current, because the focus will select the whole text and make it ugly
Private Sub Form_Current()
FocusTrap.SetFocus
End Sub
Private Sub Form_Open(Cancel As Integer)
FocusTrap.SetFocus
End Sub
' When FrontBox receives focus, switch the focus to BackBox,
' which can display the entire text
Private Sub FrontBox_GotFocus()
BackBox.SetFocus
FrontBox.Visible = False
End Sub
' When BackBox receives the focus, set the selection to
' the end of the text
Private Sub BackBox_GotFocus()
BackBox.SelStart = Len([LongNote])
BackBox.SelLength = 0
End Sub
' When BackBox loses focus, re-display FrontBox – if the text in
' BackBox has changed, then FrontBox will follow the change
Private Sub BackBox_LostFocus()
FrontBox.Visible = True
End Sub
Test the form. When you click on FrontBox, it should disappear, letting you work on BackBox. When you click in OtherBox to remove the focus from BackBox, FrontBox should reappear. Any edits made in BackBox should be reflected in FrontBox.
Back in design mode, move FrontBox so it exactly covers BackBox, and click Position | Bring to Front to ensure that it covers BackBox. Now test the form again. It should appear that a single text box switches between display-the-last-few-lines mode and edit-the-entire-contents mode.
Simply put the following code after linefeed or on Change event txtStatus
txtStatus.SelStart = Len(txtStatus) - 1

Handling carriage return/line feed in MATLAB GUI user controls

I have a MATLAB program I am developing in order to do some image processing stuff and need to use a user control into a MATLAB GUI user interface I created ad-hoc.
This user control is a List Box and there I would like to insert some text. Well the problem is not that I cannot put text there, I can do that using this call:
set(handles.mylistbox, 'String', 'MyStringToPrint');
Well the problem is that this call does not let me insert many lines in my list box but just overwrite the previous one.
I wish to find a way to let my code insert the new text in a new line. This should not be so difficult to do and it is also a simple pattern:
texttoprint = 'My text to add'
oldtext = get(handles.MyListBox, 'String') %Holding the previous text here
set(handles.MyListBox, 'String', [oldtext '\n' texttoprint]) %Setting (no line feed printed)
set(handles.MyListBox, 'String', [oldtext char(10) texttoprint]) %Setting (this fails too)
Well it is ok and it does not raise any error BUT, \n DOES NOT WORK.
I do not have any new line... BUT NEED TO!!!!
How should I solve this?
The problem is that I need to print text in this user control, not on the MATLAB commandline (that is very simple just by doing sprintf()).
What to do? Thank you
For a listbox, set the string property to a cell
set(myListboxHandle,'String',{'myFirstLine';'mySecondLine'})
If you want to add another line, call
contents = get(myListboxHandle,'String');
set(myListboxHandle,[contents;{'another line'}])
For multiline text in GUIs otherwise, use char(10) instead of \n, i.e.
set(someUiControlHandle,'String',sprintf('my first line%smy second line',char(10)))
When working with list boxes it's usually easier to deal with the options as a cell array of strings. So, you would initialize your list box as follows:
set(handles.MyListBox,'String',{'Option 1'});
And then you can add options to your list box like so:
newOption = 'Option 2';
oldOptions = get(handles.MyListBox,'String');
set(handles.MyListBox,'String',[oldOptions; {newOption}]);

clearing newline char from gtk.Textbuffer

I have a gtk.TextBuffer which is supposed to be cleared after pressing Enter, similar to the input box on most chat programs. I'm just setting the buffer back to a blank string. The newline character from Enter isn't removed though, and a blank line ends up above the cursor during the next input. Moving the cursor to the first gtk.Iter doesn't help.
By default, "gobject.connect()" callback is called before the default handler. You need to use "gobject.connect_after()".
def insert_text_cb(text_buffer, position, text, lenght):
if text == '\n':
text_buffer.set_text('')
text_view = gtk.TextView()
text_view.get_buffer().connect_after('insert-text', insert_text_cb)
Are you sure you're trigger on the proper event? Also try connecting it after.