當前位置: 首頁>>技術教程>>正文


針對高 DPI 屏幕修複基於 Java 的應用程序的縮放

, , , ,

問題描述

有些應用程序(主要基於Java)不遵循我在screen-settings中設置的global 2x scale。因此,在我的3200x1800px高DPI屏幕上,這些應用程序確實很小。

如何讓這些應用程序以較小的屏幕分辨率運行?

最佳思路

一個主要的便利升級是使用後台腳本,自動設置每個應用程序的分辨率,同時您可以一次為不同(多個)應用程序設置不同的分辨率。

這正是下麵的腳本所做的。

默認分辨率 1680x1050 的示例:

運行 gedit ,自動更改為 640x480

運行 gnome-terminal ,自動更改為 1280x1024

當應用程序關閉時,分辨率自動設置回1680x1050

如何使用

  1. 將下麵的腳本複製到一個空文件中,保存為set_resolution.py

  2. 在腳本的頭部,在行中設置默認分辨率:

    #--- set the default resolution below
    default = "1680x1050"
    #---
    
  3. 在同一個目錄(文件夾)中,創建一個文本文件,完全命名為: procsdata.txt 。在此文本文件中,設置所需的應用程序或進程,後跟一個空格,然後是所需的分辨率。每行一個應用程序或腳本,如下所示:

    gedit 640x480
    gnome-terminal 1280x1024
    java 1280x1024
    

  4. 通過以下命令運行腳本:

    python3 /path/to/set_resolution.py
    

說明

該腳本使用 pgrep -f <process> ,它捕獲所有匹配項,包括腳本。可能的缺點是在打開與進程同名的文件時可能會導致名稱衝突。如果遇到類似問題,請更改:

matches.append([p, subprocess.check_output(["pgrep", "-f", p]).decode("utf-8")])

進入:

matches.append([p, subprocess.check_output(["pgrep", p]).decode("utf-8")])

劇本

#!/usr/bin/env python3
import subprocess
import os
import time

#--- set the default resolution below
default = "1680x1050"
#---

# read the datafile
curr_dir = os.path.dirname(os.path.abspath(__file__))
datafile = curr_dir+"/procsdata.txt"
procs_data = [l.split() for l in open(datafile).read().splitlines() if not l == "\n"]
procs = [pdata[0] for pdata in procs_data]

def check_matches():
    # function to find possible running (listed) applications
    matches = []
    for p in procs:
        try:
            matches.append([p, subprocess.check_output(["pgrep", "-f", p]).decode("utf-8")])
        except subprocess.CalledProcessError:
            pass
    match = matches[-1][0] if len(matches) != 0 else None
    return match

matches1 = check_matches()

while True:
    time.sleep(2)
    matches2 = check_matches()
    if matches2 == matches1:
        pass
    else:
        if matches2 != None:
            # a listed application started up since two seconds ago
            resdata = [("x").join(item[1].split("x")) for item in \
                       procs_data if item[0] == matches2][0]
        elif matches2 == None:
            # none of the listed applications is running any more
            resdata = default
        subprocess.Popen(["xrandr", "-s", resdata])
    matches1 = matches2
    time.sleep(1)

Explanation

腳本啟動時,它將讀取您在其中定義了應用程序及其對應的所需屏幕分辨率的文件。

然後它會密切關注正在運行的進程(為每個應用程序運行 pgrep -f <process>)並在應用程序啟動時設置分辨率。

pgrep -f <process>不為任何列出的應用程序產生輸出時,它將分辨率設置為”default”。


編輯:

“Dynamic” 版本(按要求)

雖然上述版本適用於多個列出的應用程序,但它一次隻能為一個應用程序設置分辨率。

下麵的版本可以處理具有不同(所需)分辨率的不同應用程序,同時運行。後台腳本將跟蹤最前麵的應用程序,並相應地設置分辨率。它也適用於 Alt + Tab

請注意,如果您在桌麵應用程序和列出的應用程序之間進行大量切換,此行為可能會很煩人。頻繁的分辨率切換可能太多了。

如何設置的差異

設置幾乎相同,因為這個使用 wmctrlxdotool

sudo apt-get install wmctrl
sudo apt-get install xdotool

劇本

#!/usr/bin/env python3
import subprocess
import os
import sys
import time

#--- set default resolution below
resolution = "1680x1050"
#---

curr_dir = os.path.dirname(os.path.abspath(__file__))
datafile = curr_dir+"/procsdata.txt"
applist = [l.split() for l in open(datafile).read().splitlines()]
apps = [item[0] for item in applist]

def get(cmd):
    try:
        return subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
    except subprocess.CalledProcessError:
        pass

def get_pids():
    # returns pids of listed applications; seems ok
    runs = []
    for item in apps:
        pid = get("pgrep -f "+item)
        if pid != None:
            runs.append((item, pid.strip()))    
    return runs

def check_frontmost():
    # returns data on the frontmost window; seems ok
    frontmost = str(hex(int(get("xdotool getwindowfocus").strip())))
    frontmost = frontmost[:2]+"0"+frontmost[2:]
    try:
        wlist = get("wmctrl -lpG").splitlines()
        return [l for l in wlist if frontmost in l]
    except subprocess.CalledProcessError:
        pass

def front_pid():
    # returns the frontmost pid, seems ok
    return check_frontmost()[0].split()[2]

def matching():
    # nakijken
    running = get_pids(); frontmost = check_frontmost()
    if all([frontmost != None, len(running) != 0]):
        matches = [item[0] for item in running if item[1] == frontmost[0].split()[2]]
        if len(matches) != 0:
            return matches[0]
    else:
        pass

trigger1 = matching()

while True:
    time.sleep(1)
    trigger2 = matching()
    if trigger2 != trigger1:
        if trigger2 == None:
            command = "xrandr -s "+resolution
        else:
            command = "xrandr -s "+[it[1] for it in applist if it[0] == trigger2][0]
        subprocess.Popen(["/bin/bash", "-c", command])
        print(trigger2, command)
    trigger1 = trigger2

說明

  • 雖然我現在已經運行了幾個小時沒有錯誤,但請徹底測試它。如果可能發生錯誤,請發表評論。

  • 該腳本原樣適用於單個監視器設置。

次佳思路

測試添加到您的 java 命令行: -Dsun.java2d.uiScale=2.0 ,或將其設置為您想要的比例因子。

參考資料

本文由Ubuntu問答整理, 博文地址: https://ubuntuqa.com/zh-tw/article/11884.html,未經允許,請勿轉載。