I am trying to write a GUI that will allow user to
1) create as many as draggable circles after pushing Add Circle button
I designed the function as below. It inserts fixed sized circles on the image each time I hit 'add' button. I count the push button hit number, too (in case I use it as a loop index)
function Add_Callback(hObject, eventdata, handles)
% hObject handle to Add (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
diameter = 30;
handles.trap = imellipse(gca,[100, 100, diameter, diameter]);
addNewPositionCallback(handles.trap ,#(p) title(mat2str(p,3)));
fcn = makeConstrainToRectFcn('imellipse',get(gca,'XLim'),get(gca,'YLim'));
setFixedAspectRatioMode(handles.trap,'True');
setPositionConstraintFcn(handles.trap,fcn);
wait(handles.trap);
handles.count = handles.count+1
guidata(hObject, handles);
2) drag them to desired positions - It is automatically done by Matlab :)
3) select the active circle (e.g. set_as_Active function) - Here is the problem.
4) delete the one that the user think is unnecessary with a button (e.g. Delete_Circle) or with double click if possible
Since I can not select the active circle, when I hit delete, it deletes the updated handle object and next time it gives error.
delete(handles.trap);
guidata(hObject, handles);
I have used imellipse function to add draggable circles. However, I could not update the positions of the circles and select the desired circle as active. How can I do that?
Thanks for the helps.
Related
I have wrapping NSTextView instances stacked vertically, for example:
The quick brown fox
jumps over the lazy dog
Jackdaws love my big
sphinx of quartz
I need to move between them with up/down arrows. For example, when the cursor is positioned after the l in "lazy" and the user presses the down arrow, the cursor should jump right after the y in "my" – like it would do if these sentences were in the same text view.
By default, when the down arrow is pressed while the cursor is at the last wrapped line, a text view moves it to the end of that line. While I can use textView(_:doCommandBy:) in NSTextViewDelegate to detect the "arrow down" selector and override the default behavior, there are two problems:
I can determine if the cursor is at the last line by getting its position via the selectedRanges property and then checking for the newline character after this position, but it is not possible to know if it is at the last wrapped line, i.e. near the border of the current text view.
I need to know the X coordinate of the cursor to place it at approximately the same X coordinate in another text view (the fonts won't necessarily be fixed-width, so I can't rely on the character count).
I suppose both of them can be resolved via NSLayoutManager, but I can't wrap my head around all of its available methods.
It turned out to be relatively easy, here's what I've done (the examples are in C#). First, boundingRect(forGlyphRange:in:) gets the cursor's location in the current view:
var cursorLocation = new NSRange(CurrentTextView.SelectedRange.Location, 0);
var cursorCoordinates = CurrentTextView.LayoutManager.BoundingRectForGlyphRange(cursorLocation, CurrentTextView.TextContainer).Location;
Then if the second text view is below, the insertion point will be at 0 on the Y axis:
var insertionPoint = new CGPoint(cursorCoordinates.X, 0);
And if it is above, then another view's height should be used (reduced by 1, otherwise the resulting character index will be incorrect and the cursor will be placed at the end of the line):
var insertionPoint = new CGPoint(cursorCoordinates.X, AnotherTextView.Bounds.Size.Height - 1);
After getting the insertion point, another view needs to become the first responder and then characterIndexForInsertion(at:) does the job:
Window.MakeFirstResponder(AnotherTextView);
var index = AnotherTextView.CharacterIndex(insertionPoint);
AnotherTextView.SelectedRange = new NSRange(index, 0);
I have an FMX form with a TLayout on it aligned to client. On the TLayout I have a TRectangle. I can move the TRectangle easily with the following code in a button click event:
Rectangle1->Position->X = Rectangle1->Position->X + 10;
Is there a clean way for me to do this (move the rectangle) with the mouse? Like click on the Rectangle and move it around to a new location? I'm just playing around trying to make a little drawing program to learn....
Using C++Builder 10.2 Version 25.0.29899.2631 and building in Win32.
UPDATE: I took Hans approach and ended up making it work nicely. I've added the full code as an answer below. Yay!
A way to drag components is to store the offset between the mouse position and the control position on mouse down, then use this offset to calculate the position of the control in the mouse move event.
In semi-pseudo code it would look like this:
Add the following to your TForm class:
fMouseIsDown: boolean;
fMouseDownOffset: TPointF;
procedure OnRectangleMouseDown(X,Y)
begin
fMouseIsDown := true;
fMouseDownOffset := PointF(Rectangle.Position.X-X, Rectangle.Position.Y-Y)
end;
procedure OnRectangleMouseMove(X,Y)
begin
if fMouseIsDown then
begin
Rectangle.Position.X := X+fMouseDownOffset.X;
Rectangle.Position.Y := Y+fMouseDownOffset.Y;
end;
end;
procedure OnRectangleMouseUp(X,Y);
begin
fMouseIsDown := false;
end;
Here is the complete code needed to left-click on and move a TRectangle on an FMX form in Win32 (haven't tried it on mobile yet). Just create a new FireMonkey multi-device application and put a TRectangle and a TButton on it.
Code to add to the forms's class declaration (in the .h file just under class TForm1 : public TForm {):
bool fMouseIsDown; // gets set to TRUE when left mouse click on the rectangle
TPointF fMousePosGlobal; // this is the mouses position relative to the screen
TPointF fMousePosForm; // this is the mouse pos relative to the form
TPointF captionOffset; // this is a small offset necessary since the form's TOP and LEFT are outside of form's client area due to caption bar and left edge of form
TPointF fMouseInRectAtClick; // this is the mouse pos relative to the rectangle (top left of rectangle is 0,0)
Code to add to the rectangle's Rectangle1MouseDown event:
if (Button == 0) { // 0 for left mb, 1 for right mb
fMouseIsDown = true;
fMouseInRectAtClick.X = X; //mouse pos with respect to rectangle at time of click
fMouseInRectAtClick.Y = Y;
}
Code to add to the rectangle's Rectangle1MouseMove event (add to the form's FormMouseMove too or sometimes you lose the rectangle on a fast drag):
fMousePosGlobal = Screen->MousePos(); //mouse global pos
fMousePosForm.X = fMousePosGlobal.X - Form1->Left; // mouse pos relative to the form
fMousePosForm.Y = fMousePosGlobal.Y - Form1->Top;
if (fMouseIsDown) {
Form1->Rectangle1->Position->X = fMousePosForm.X - captionOffset.X - fMouseInRectAtClick.X;
Form1->Rectangle1->Position->Y = fMousePosForm.Y - captionOffset.Y - fMouseInRectAtClick.Y;
}
Code to add to the Rectangle1MouseUp event:
fMouseIsDown = false; // add this to the form's MouseUp too in case you "lose" the rectangle on a drag. That only happened when i forget to set the offsets.
Code to add to the Button's Button1Click event:
captionOffset.X = 8.0; // this accounts for the width of the form left edge
captionOffset.Y = 30.0; // this accounts for the height of the form caption
// if you don't add this your "drag point" on the rectangle will jump as soon as you start the drag.
Thanks to Hans for the direction to start!
Also, i noticed the drag wasn't smooth when moving across other controls. If this bothers you then you need to set those other controls "HitTest" false so they ignore it. Add TEdit boxes if you want to see all the TPointF coordinates as you move mouse and rectangle - helps a bunch when trying to figure out coordinates.
I'm writing a complex color editing dialog box which contains a list view control and a photoshop-style HSV color picker. This dialog will be used as described:
the user first clicks on the particular item, then manipulates cursor on the colorpicker to setup the right color for the item, then clicks another item and repeats the process.
My hotoshop stle HSV colorpicker is devided in two rectangels -
1. 256x20 color ramp that represents with full 360 span of HUEs
256x256 window that showes all the VALUES and SATURATION variation of the current selected HUE.
Realization:
I've made some research and decided to use GDI bitmaps.
So I fill in GDI BITMAP struct, get dc, get comaptable dc, and create hBitmap by CreateBitmapIndirect:
case WM_INITDIALOG:
bitmap_hsv.bmBits=&bits_hsv;
bitmap_hsv.bmBitsPixel=32;
bitmap_hsv.bmHeight=256;
bitmap_hsv.bmPlanes=1;
bitmap_hsv.bmType=0;
bitmap_hsv.bmWidth=256;
bitmap_hsv.bmWidthBytes=256*4;
hDC=GetDC(hDlg);
hDC_compat=CreateCompatibleDC(hDC);
hBitmap_hsv=CreateBitmapIndirect(&bitmap_hsv);
return (INT_PTR)TRUE;
Then on the mouse move I have to check if the user selected some other HUE in the hue ramp and if he did then I need to fill the byte array of my BITMAP by new values. In the listing for simplicity reasons every mouse move need change of HUE and refill the whole bitmap each call.
case WM_MOUSEMOVE:
if (wParam&MK_LBUTTON)
{
hDC=GetDC(hDlg);
pt.x=(LONG) LOWORD(lParam);//client coords
pt.y=(LONG) HIWORD(lParam);//client coords
H+=1;
if (H==360) H=0;
fill_bits_hsv(H,bits_hsv,4);
hBitmap_hsv=CreateBitmapIndirect(&bitmap_hsv);
if (!hBitmap_hsv)
{
err=GetLastError();
return 0;//I STOP CODE HERE TO SEE err=0;
}
SelectObject(hDC_compat,hBitmap_hsv);
BitBlt(hDC,0,0,255,255,hDC_compat,10,10,SRCCOPY);
drawCursor(pt.x,pt.y,hDC);
ReleaseDC(hDlg,hDC);
}
return 0;
It works ok for 40 or 50 first calls, but then all the window lags and looses DC, I can move the window, but the area is not refreshing. My stop mark shows the problem with
hBitmap=CreateBitmapIndirect(...) which shows 0x00000000 and GetLastError shows 0;
And now the main question what am I doing wrong?
I have an image opened in an axes object inside a GUIDE MATLAB GUI. I want to be able to update some variables depending in the position of the cursor over the image. My effort in order to achieve it has been to use the following code to set the behavior of the axes:
pointerBehavior.enterFcn = [];
pointerBehavior.exitFcn = [];
pointerBehavior.traverseFcn = #(figHandle, currentPoint)CoordChanger(figHandle,currentPoint, hObject, handles);
iptSetPointerBehavior(handles.axes1, pointerBehavior);
iptPointerManager(gcf);
With the following function:
function CoordChanger(figh, cp, hObject, handles)
handles.output = hObject;
CursorPosition = get(handles.axes1,'CurrentPoint')
guidata(hObject, handles);
However when I look at the CursorPosition value while I’m moving the cursor along the image it always shows the same value. What am I doing wrong? Is there any other way to achieve the same result?
Look at the cp variable inside CoordChanger, you should see the cursor position changing there.
I've created one image editor window in MATLAB, which includes various operations including brightness, contrast, crop, rotate etc.., In this GUI, each operations has its own function call backs.
My problem is with linking one function with another. if i crop image, then if i change brightness my current code changes brightness of original image rather than cropped image.
similarly at first i if change brightness and then if i crop, my code will crop original image rather than brightened image.
Below code is to change brightness.
function slider2_Callback(hObject, eventdata, handles)
fname = getappdata(0, 'fname');
[a, map] = imread(fname);
x = ind2rgb(a, map);
b = get(handles.slider2,'value');
j = imadjust(x,[],[],b);
axes(handles.axes1);
imshow(j);
Below code is to crop
function crop_Callback(hObject, eventdata, handles)
fname = getappdata(0, 'fname');
[a, map] = imread(fname);
x = ind2rgb(a, map);
new = imcrop(x);
axes(handles.axes1);
imshow(new);
Suppose say at first if i crop image, then next step if i change brightness of cropped image later some other operation on above edited image, How can i link one operation with another?
I think it's because you are not updating your handles after changing them, hence the code is still referring to the old handle.
Try guidata(hObject, handles); right after cropping.
Instead of having global variable for the file name, you need to have a global variable for the image. So in each of your callbacks you can manipulate with your image without reading the image every time. Also, you should keep your changes at the end of each call back by setappdata. Thus, your callbacks would be something like this:
function changeimage_Callback(hObject, eventdata, handles)
image = getappdata(0, 'image');
% manipulation on image
% show image
setappdata(0, 'image', image);
If you have one GUI, I think it would be more convenient if you do such a thing with handles. That is, load your image in your GUI and keep it like this:
handles.image = imread(filename);
guidata(hObject, handles);
Then your callbacks would be like this:
function changeimage_Callback(hObject, eventdata, handles)
% manipulation on handles.image
% show handles.image
guidata(hObject, handles);
Instead of loading the original image file to perform your manipulation on, load the image from the figure.
In other words, replace
fname = getappdata(0, 'fname');
[a, map] = imread(fname);
x = ind2rgb(a, map);
with
x = getimage(handles.axes1);
I didn't test the code but it should fix your problem with a minimal amount of work.