macos 允许单击并拖动视图来拖动窗口本身吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4563893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Allow click and dragging a view to drag the window itself?
提问by d11wtq
I'm using a textured window that has a tab bar along the top of it, just below the title bar.
我正在使用一个带纹理的窗口,它的顶部有一个标签栏,就在标题栏的下方。
I've used -setContentBorderThickness:forEdge:
on the window to make the gradient look right, and to make sure sheets slide out from the right position.
我-setContentBorderThickness:forEdge:
在窗口上使用过使渐变看起来正确,并确保纸张从正确的位置滑出。
What's not working however, is dragging the window around. It works if I click and drag the area that's actually the title bar, but since the title bar gradient spills into a (potentially/often empty) tab bar, it's reallyeasy to click too low and it feels really frustrating when you try to drag and realise the window is not moving.
然而,不起作用的是拖动窗口。如果我单击并拖动实际上是标题栏的区域,它会起作用,但是由于标题栏渐变溢出到(可能/通常是空的)标签栏,点击太低真的很容易,当你尝试拖动时感觉真的很令人沮丧并意识到窗口没有移动。
I notice NSToolbar
, while occupying roughly the same amount of space below the title bar, allows the window to be dragged around when the cursor is over it. How does one implement this?
我注意到NSToolbar
,虽然在标题栏下方占据大致相同的空间,但允许在光标悬停在其上方时拖动窗口。如何实现这一点?
Thanks.
谢谢。
采纳答案by d11wtq
I found this here:
我在这里找到了这个:
-(void)mouseDown:(NSEvent *)theEvent {
NSRect windowFrame = [[self window] frame];
initialLocation = [NSEvent mouseLocation];
initialLocation.x -= windowFrame.origin.x;
initialLocation.y -= windowFrame.origin.y;
}
- (void)mouseDragged:(NSEvent *)theEvent {
NSPoint currentLocation;
NSPoint newOrigin;
NSRect screenFrame = [[NSScreen mainScreen] frame];
NSRect windowFrame = [self frame];
currentLocation = [NSEvent mouseLocation];
newOrigin.x = currentLocation.x - initialLocation.x;
newOrigin.y = currentLocation.y - initialLocation.y;
// Don't let window get dragged up under the menu bar
if( (newOrigin.y+windowFrame.size.height) > (screenFrame.origin.y+screenFrame.size.height) ){
newOrigin.y=screenFrame.origin.y + (screenFrame.size.height-windowFrame.size.height);
}
//go ahead and move the window to the new location
[[self window] setFrameOrigin:newOrigin];
}
It works fine, though I'm not 100% sure I'm doing it correctly. There's one bug I've found so far, and that's if the drag begins inside a subview (a tab itself) and then enters the superview (the tab bar). The window jumps around. Some -hitTest: magic, or possibly even just invalidating initialLocation on mouseUp should probably fix that.
它工作正常,尽管我不是 100% 确定我做对了。到目前为止,我发现了一个错误,那就是如果拖动从子视图(选项卡本身)内开始,然后进入超级视图(选项卡栏)。窗户跳来跳去。一些 -hitTest: 魔法,或者甚至可能只是使 mouseUp 上的 initialLocation 无效应该可以解决这个问题。
回答by ArtOfWarfare
I tried the mouseDownCanMoveWindow
solution (https://stackoverflow.com/a/4564146/901641) but it didn't work for me. I got rid of that method and instead added this to my window subclass:
我尝试了mouseDownCanMoveWindow
解决方案(https://stackoverflow.com/a/4564146/901641),但对我不起作用。我摆脱了该方法,而是将其添加到我的窗口子类中:
- (BOOL)isMovableByWindowBackground {
return YES;
}
which worked like a charm.
这就像一个魅力。
回答by Richard
Have you tried overriding the NSView method mouseDownCanMoveWindow
to return YES
?
您是否尝试覆盖 NSView 方法mouseDownCanMoveWindow
以返回YES
?
回答by Nix Wang
It works for me after TWO steps:
它在两个步骤后对我有用:
- Subclass NSView, override the
mouseDownCanMoveWindow
to return YES. - Subclass NSWindow, override the
isMovableByWindowBackground
to return YES.
- 子类 NSView,覆盖
mouseDownCanMoveWindow
返回 YES。 - 子类 NSWindow,覆盖
isMovableByWindowBackground
返回 YES。
回答by Dimitri Bouniol
As of macOS 10.11, the simplest way to do this is to utilize the new -[NSWindow performWindowDragWithEvent:]
method:
从 macOS 10.11 开始,最简单的方法是使用新-[NSWindow performWindowDragWithEvent:]
方法:
@interface MyView () {
BOOL movingWindow;
}
@end
@implementation MyView
...
- (BOOL)mouseDownCanMoveWindow
{
return NO;
}
- (void)mouseDown:(NSEvent *)event
{
movingWindow = NO;
CGPoint point = [self convertPoint:event.locationInWindow
fromView:nil];
// The area in your view where you want the window to move:
CGRect movableRect = CGRectMake(0, 0, 100, 100);
if (self.window.movableByWindowBackground &&
CGRectContainsPoint(movableRect, point)) {
[self.window performWindowDragWithEvent:event];
movingWindow = YES;
return;
}
// Handle the -mouseDown: as usual
}
- (void)mouseDragged:(NSEvent *)event
{
if (movingWindow) return;
// Handle the -mouseDragged: as usual
}
@end
Here, -performWindowDragWithEvent:
will handle the correct behavior of not overlapping the menu bar, and will also snap to edges on macOS 10.12 and later. Be sure to include a BOOL movingWindow
instance variable with your view's private interface so you can avoid -mouseDragged:
events once you determined you don't want to process them.
在这里,-performWindowDragWithEvent:
将处理不重叠菜单栏的正确行为,并且还将在 macOS 10.12 及更高版本上对齐边缘。确保BOOL movingWindow
在视图的私有接口中包含一个实例变量,这样-mouseDragged:
一旦确定不想处理事件,就可以避免发生事件。
Here, we are also checking that -[NSWindow movableByWindowBackground]
is set to YES
so that this view can be used in non-movable-by-window-background windows, but that is optional.
在这里,我们还检查-[NSWindow movableByWindowBackground]
设置为,YES
以便此视图可以在不可移动的窗口背景窗口中使用,但这是可选的。
回答by D.A.H
It's quite easy:
这很容易:
override mouseDownCanMoveWindowproperty
覆盖mouseDownCanMoveWindow属性
override var mouseDownCanMoveWindow:Bool {
return false
}
回答by Paulo Mattos
If you got a NSTableView
in your window, with selection enabled, overriding the mouseDownCanMoveWindow
property won't work.
如果您NSTableView
的窗口中有 ,并且选择已启用,则覆盖该mouseDownCanMoveWindow
属性将不起作用。
You need instead to create a NSTableView
subclass and override the following mouse events (and use the performWindowDragWithEvent:
mentioned in Dimitri answer):
您需要创建一个NSTableView
子类并覆盖以下鼠标事件(并使用Dimitri answer 中performWindowDragWithEvent:
提到的):
@interface WindowDraggableTableView : NSTableView
@end
@implementation WindowDraggableTableView
{
BOOL _draggingWindow;
NSEvent *_mouseDownEvent;
}
- (void)mouseDown:(NSEvent *)event
{
if (self.window.movableByWindowBackground == NO) {
[super mouseDown:event]; // Normal behavior.
return;
}
_draggingWindow = NO;
_mouseDownEvent = event;
}
- (void)mouseDragged:(NSEvent *)event
{
if (self.window.movableByWindowBackground == NO) {
[super mouseDragged:event]; // Normal behavior.
return;
}
assert(_mouseDownEvent);
_draggingWindow = YES;
[self.window performWindowDragWithEvent:_mouseDownEvent];
}
- (void)mouseUp:(NSEvent *)event
{
if (self.window.movableByWindowBackground == NO) {
[super mouseUp:event]; // Normal behavior.
return;
}
if (_draggingWindow == YES) {
_draggingWindow = NO;
return; // Event already handled by `performWindowDragWithEvent`.
}
// Triggers regular table selection.
NSPoint locationInWindow = event.locationInWindow;
NSPoint locationInTable = [self convertPoint:locationInWindow fromView:nil];
NSInteger row = [self rowAtPoint:locationInTable];
if (row >= 0 && [self.delegate tableView:self shouldSelectRow:row])
{
NSIndexSet *rowIndex = [NSIndexSet indexSetWithIndex:row];
[self selectRowIndexes:rowIndex byExtendingSelection:NO];
}
}
@end
Also don't forget to set the corresponding window movableByWindowBackground
property as well:
另外不要忘记设置相应的窗口movableByWindowBackground
属性:
self.window.movableByWindowBackground = YES;
回答by Ely
When you set property isMovableByWindowBackground
in viewDidLoad
, it may not work because the window
property of the view
is not yet set. In that case, try this:
当您在 中设置属性isMovableByWindowBackground
时viewDidLoad
,它可能不起作用,因为 的window
属性view
尚未设置。在这种情况下,试试这个:
override func viewDidAppear() {
self.view.window?.isMovableByWindowBackground = true
}