nw.js node-webkit系列(13)Native UI API 其它

本节主要介绍Native UI API中一些不常用的功能,包括Shell、Handling files and arguments、Screen。

(一)Shell

Shell主要用来处理桌面相关应用的工作。如使用默认浏览器打开一个网页地址、使用文本的方式打开一个文件、在文件资源管理器中打开文件。

// Load native UI library.
var gui = require('nw.gui');

// Open URL with default browser.
gui.Shell.openExternal('https://github.com/rogerwang/node-webkit');

// Open a text file with default text editor.
gui.Shell.openItem('test.txt');

// Open a file in file explorer.
gui.Shell.showItemInFolder('test.txt');

(二)NW应用处理文件和参数的方式

针对一些应用,例如文本编辑器和IDE,它可以绑定文件类型并指定特定的APP打开,这个功能是很重要的。

Command line arguments

命令行参数传输。在node-webkit中,当使用命令行去指定你的APP去打开一个文件时,如

your-app file.txt file2.txt

其中

file.txt file2.txt
将会被记录而且你能够使用App.argv的方法去获取它们,如

var gui = require('nw.gui');
console.log(gui.App.argv);
// Print "file.txt, file2.txt"

Open file with existing app

使用现有的应用打开文件。在很多时候,当你使用你的APP打开多个文件时,你更希望使用一个APP会话去打开而不是多个会话。例如,一个IDE,如果你已经打开了一个IDE实例,然后再打开一个源码文件,你会希望使用已打开的IDE实例去编辑文件而不是重新打开一个IDE实例。

对于node-webkit的应用,这个问题已经被默认解决了。当你打开一个文件,node-webkit会检测你的APP是否已经打开,如果没有打开,你的应用实例将会被打开并且文件的路径会从App.argv中获取;如果你的应用已经在打开的状态,那么整个命令行的内容将会通过open事件监听到APP对象获取。两种情况获取的打开文件的参数对象方式不同。

// Listen to `open` event
gui.App.on('open', function(cmdline) {
  console.log('command line: ' + cmdline);
});

注:open事件只有在你的APP是独立存在的情况下生效。例如使用这种方式进行打包:

https://github.com/nwjs/nw.js/wiki/How-to-package-and-distribute-your-apps

注:在苹果系统,如果以文件拖动到你的APP图标中的方式打开文件,open事件依然有效。

注:在苹果系统,你应该注册你的文件类型,使文件启动类型指向你的APP。操作方法参照:

https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Articles/RegisteringtheFileTypesYourAppSupports.html

注:如果你不想使用这个功能,在Windows和Linux系统下,你可以在package配置文件中设置single-instance为false。然而这个设置对苹果系统并没有效果。


(三)Screen

Screen是EventEmitter对象的一个实例。你可以使用Screen.on(...)去回应本地屏幕事件。

Screen是一个独立的对象,它需要被初始化当使用的时候。如gui.Screen.Init()。


Screen.Init()

初始化Screen实例对象,你只需要调用一次即可。


Screen.screens

获取Screen实例对象的数据。Screen对象有以下的结构:

screen {
// unique id for a screen
  id: int,

// physical screen resolution, can be negative, not necessarily start from 0,depending on screen arrangement
  bounds: {
    x: int,
    y: int,
    width: int,
    height: int
  },

// useable area within the screen bound
  work_area: {
    x: int,
    y: int,
    width: int,
    height: int
  },

  scaleFactor: float,
  isBuiltIn: bool,
  rotation: int,
  touchSupport: int
}

Screen.chooseDesktopMedia (array of DesktopCaptureSourceType sources, function callback)

该功能比较复杂,详细请参考:

https://github.com/nwjs/nw.js/issues/3077


更多对屏幕控制的函数,请参考

https://github.com/nwjs/nw.js/wiki/Screen


(四)小贴士

(1)Show window after page is ready

通常情况下,node-webkit打开一个APP,需要通过以下步骤:

1).显示浏览器

2).解压你的APP

3).创建渲染过程

4).初始化webkit

5).最后打开你的APP

这个过程需要些时间,而且这段时间用户将看到一个空的浏览器。这会导致看起来你的APP运行的非常缓慢,你应该等所有都准备就绪后才显示你的主窗口。针对这个问题,下面有些小贴士可以提供给你。

首先,你需要在package配置文件中设置窗口的显示为false,这样在node-webkit启动时便不会显示窗口。

{
  "window": {
    "show": false
  }
}

当所有都准备就绪后,你再调用Windows API把窗口显示出来。

<script>
var gui = require('nw.gui');

onload = function() {
  gui.Window.get().show();
}
</script>

(2)Minimize to tray

在windows系统中,一种通用的窗口设计模式是最小化窗口时会到通知区域。如当点击窗口的最小化按钮时,会最小化到托盘,点击托盘将返回窗口。

为了在node-webkit中实现这种功能,你可以使用以下代码:

<html>
<body>
  <div>Minimize to tray</div>
  <script>
    // Load library
    var gui = require('nw.gui');

    // Reference to window and tray
    var win = gui.Window.get();
    var tray;

    // Get the minimize event
    win.on('minimize', function() {
      // Hide window
      this.hide();

      // Show tray
      tray = new gui.Tray({ icon: 'icon.png' });

      // Show window and remove tray when clicked
      tray.on('click', function() {
        win.show();
        this.remove();
        tray = null;
      });
    });
  </script>
</body>
</html>

(3)Preserve window state between sessions

在多次会话中保存窗口的状态。意思是当首次打开窗口时,将窗口的位置和宽高记录在node-webkit的Local Storage中,下次打开窗口时,恢复上次窗口的显示状态。

为了实现这个功能,首先你需要把窗口的显示状态设为false:

{
  "window": {
    "show": false
  }
}

然后你可以使用下面这段代码:

/**
 * https://github.com/nwjs/nw.js/wiki/Preserve-window-state-between-sessions
 *
 * Cross-platform window state preservation.
 * Yes this code is quite complicated, but this is the best I came up with for
 * current state of node-webkit Window API (v0.7.3 and later).
 *
 * Known issues:
 * - Unmaximization not always sets the window (x, y) in the lastly used coordinates.
 * - Unmaximization animation sometimes looks wierd.
 * - Extra height added to window, at least in linux x64 gnome-shell env. It seems that
 *   when we read height then it returns it with window frame, but if we resize window
 *   then it applies dimensions only to internal document without external frame.
 *   Need to test in other environments with different visual themes.
 *
 * Change log:
 * 2013-12-01
 * - Workaround of extra height in gnome-shell added.
 *
 * 2014-03-22
 * - Repared workaround (from 2013-12-01) behaviour when use frameless window.
 *   Now it works correctly.
 * 2014-10-02
 * - Fixed cannot set windowState of null error when attempting to set localStorage
 *
 * 2015-03-05
 * - Don't call window.show() if dev tools are already open (see initWindowState).
 *
 * 2015-06-15
 * - Don't resize the window when using LiveReload.
 */

var gui = require('nw.gui');
var win = gui.Window.get();
var winState;
var currWinMode;
var resizeTimeout;
var isMaximizationEvent = false;
// extra height added in linux x64 gnome-shell env, use it as workaround
var deltaHeight = gui.App.manifest.window.frame ? 0 : 'disabled';


function initWindowState() {
	// Don't resize the window when using LiveReload.
	// There seems to be no way to check whether a window was reopened, so let's
	// check for dev tools - they can't be open on the app start, so if
	// dev tools are open, LiveReload was used.
	if (!win.isDevToolsOpen()) {
		winState = JSON.parse(localStorage.windowState || 'null');

		if (winState) {
			currWinMode = winState.mode;
			if (currWinMode === 'maximized') {
				win.maximize();
			} else {
				restoreWindowState();
			}
		} else {
			currWinMode = 'normal';
			dumpWindowState();
		}

		win.show();
	}
}

function dumpWindowState() {
	if (!winState) {
		winState = {};
	}

	// we don't want to save minimized state, only maximized or normal
	if (currWinMode === 'maximized') {
		winState.mode = 'maximized';
	} else {
		winState.mode = 'normal';
	}

	// when window is maximized you want to preserve normal
	// window dimensions to restore them later (even between sessions)
	if (currWinMode === 'normal') {
		winState.x = win.x;
		winState.y = win.y;
		winState.width = win.width;
		winState.height = win.height;

		// save delta only of it is not zero
		if (deltaHeight !== 'disabled' && deltaHeight !== 0 && currWinMode !== 'maximized') {
			winState.deltaHeight = deltaHeight;
		}
	}
}

function restoreWindowState() {
	// deltaHeight already saved, so just restore it and adjust window height
	if (deltaHeight !== 'disabled' && typeof winState.deltaHeight !== 'undefined') {
		deltaHeight = winState.deltaHeight
		winState.height = winState.height - deltaHeight
	}


	//Make sure that the window is displayed somewhere on a screen that is connected to the PC. 
	//Imagine you run the program on a secondary screen connected to a laptop - and then the next time you start the 
	//program the screen is not connected...
	gui.Screen.Init();
	var screens = gui.Screen.screens;
	var locationIsOnAScreen = false;
	for (var i = 0; i < screens.length; i++) {
		var screen = screens[i];
		if (winState.x > screen.bounds.x && winState.x < screen.bounds.x + screen.bounds.width) {
			if (winState.y > screen.bounds.y && winState.y < screen.bounds.y + screen.bounds.height) {
				console.debug("Location of window (" + winState.x + "," + winState.y + ") is on screen " + JSON.stringify(screen));
				locationIsOnAScreen = true;
			}
		}
	}

	if (!locationIsOnAScreen) {
		console.debug("Last saved position of windows is not usable on current monitor setup. Moving window to center!");
		win.setPosition("center");
	} else {
		win.resizeTo(winState.width, winState.height);
		win.moveTo(winState.x, winState.y);
	}
}

function saveWindowState() {
	dumpWindowState();
	localStorage['windowState'] = JSON.stringify(winState);
}

initWindowState();

win.on('maximize', function() {
	isMaximizationEvent = true;
	currWinMode = 'maximized';
});

win.on('unmaximize', function() {
	currWinMode = 'normal';
	restoreWindowState();
});

win.on('minimize', function() {
	currWinMode = 'minimized';
});

win.on('restore', function() {
	currWinMode = 'normal';
});

win.window.addEventListener('resize', function() {
	// resize event is fired many times on one resize action,
	// this hack with setTiemout forces it to fire only once
	clearTimeout(resizeTimeout);
	resizeTimeout = setTimeout(function() {

		// on MacOS you can resize maximized window, so it's no longer maximized
		if (isMaximizationEvent) {
			// first resize after maximization event should be ignored
			isMaximizationEvent = false;
		} else {
			if (currWinMode === 'maximized') {
				currWinMode = 'normal';
			}
		}

		// there is no deltaHeight yet, calculate it and adjust window size
		if (deltaHeight !== 'disabled' && deltaHeight === false) {
			deltaHeight = win.height - winState.height;

			// set correct size
			if (deltaHeight !== 0) {
				win.resizeTo(winState.width, win.height - deltaHeight);
			}
		}

		dumpWindowState();

	}, 500);
}, false);

win.on('close', function() {
	try {
		saveWindowState();
	} catch (err) {
		console.log("winstateError: " + err);
	}
	this.close(true);
});

最后,在html中导入这段代码即可

<!-- use your own path -->
<script src="lib/winstate.js"></script>


本节内容就介绍到这,如果后续博主发现更多Native UI API的相关功能,会继续在CSDN博客中发表,至此Native UI API相关功能已经介绍完毕

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值