화면 정보
디스플레이와 모니터에 관한 정보 가져오기
화면 정보
Wails는 모든 플랫폼에서 작동하는 통합 화면 API를 제공합니다. 일관된 코드로 화면 정보를 가져오고, 여러 모니터를 감지하고, 화면 속성(크기, 위치, DPI)을 조회하고, 주 디스플레이를 식별하고, DPI 배율을 처리할 수 있습니다.
빠른 시작
go
// Get all screens
screens := app.Screen.GetAll()
for _, screen := range screens {
fmt.Printf("Screen: %s (%dx%d)\n",
screen.Name, screen.Size.Width, screen.Size.Height)
}
// Get primary screen
primary := app.Screen.GetPrimary()
fmt.Printf("Primary: %s\n", primary.Name)이게 전부입니다! 크로스 플랫폼 화면 정보를 사용할 수 있습니다.
화면 정보 가져오기
모든 화면
go
screens := app.Screen.GetAll()
for _, screen := range screens {
fmt.Printf("ID: %s\n", screen.ID)
fmt.Printf("Name: %s\n", screen.Name)
fmt.Printf("Size: %dx%d\n", screen.Size.Width, screen.Size.Height)
fmt.Printf("Position: %d,%d\n", screen.X, screen.Y)
fmt.Printf("Scale: %.2f\n", screen.ScaleFactor)
fmt.Printf("Primary: %v\n", screen.IsPrimary)
fmt.Println("---")
}주 화면
go
primary := app.Screen.GetPrimary()
fmt.Printf("Primary screen: %s\n", primary.Name)
fmt.Printf("Resolution: %dx%d\n", primary.Size.Width, primary.Size.Height)
fmt.Printf("Scale factor: %.2f\n", primary.ScaleFactor)현재 화면
창이 표시된 화면을 가져옵니다:
go
screen, err := window.GetScreen()
if err != nil {
// handle error
}
fmt.Printf("Window is on: %s\n", screen.Name)ID로 화면 가져오기
go
screen := app.Screen.GetByID("screen-id")
if screen != nil {
fmt.Printf("Found screen: %s\n", screen.Name)
}화면 속성
화면 구조
go
type Screen struct {
ID string // Unique identifier
Name string // Display name
ScaleFactor float32 // DPI scale (1.0, 1.5, 2.0, etc.)
X, Y int // Position (top-left, logical pixels)
Size Size // Logical size (Width, Height)
Bounds Rect // Logical bounds (X, Y, Width, Height)
PhysicalBounds Rect // Physical bounds (scaled)
WorkArea Rect // Logical work area excluding taskbars/menubars
PhysicalWorkArea Rect // Physical work area
IsPrimary bool // Is this the primary screen?
Rotation float32 // Screen rotation in degrees (e.g. 0, 90, 180, 270)
}
// Size and Rect are simple value types:
type Size struct{ Width, Height int }
type Rect struct{ X, Y, Width, Height int }픽셀 크기는 screen.Size.Width / screen.Size.Height를 통해 읽습니다. 최상위 Width/Height 필드는 없습니다.
물리 픽셀과 논리 픽셀
go
screen := app.Screen.GetPrimary()
// Logical pixels (what you use)
logicalWidth := screen.Size.Width
logicalHeight := screen.Size.Height
// Physical pixels (actual display)
physicalWidth := int(float32(screen.Size.Width) * screen.ScaleFactor)
physicalHeight := int(float32(screen.Size.Height) * screen.ScaleFactor)
fmt.Printf("Logical: %dx%d\n", logicalWidth, logicalHeight)
fmt.Printf("Physical: %dx%d\n", physicalWidth, physicalHeight)
fmt.Printf("Scale: %.2f\n", screen.ScaleFactor)일반적인 배율:
1.0- 표준 DPI(96 DPI)1.25- 125% 배율(120 DPI)1.5- 150% 배율(144 DPI)2.0- 200% 배율(192 DPI) - Retina3.0- 300% 배율(288 DPI) - 4K/5K
창 배치
화면 중앙에 배치
go
func centreOnScreen(window *application.WebviewWindow, screen *Screen) {
windowWidth, windowHeight := window.Size()
x := screen.X + (screen.Size.Width-windowWidth)/2
y := screen.Y + (screen.Size.Height-windowHeight)/2
window.SetPosition(x, y)
}특정 화면에 배치
go
func moveToScreen(window *application.WebviewWindow, screenIndex int) {
screens := app.Screen.GetAll()
if screenIndex < 0 || screenIndex >= len(screens) {
return
}
screen := screens[screenIndex]
// Centre on target screen
centreOnScreen(window, screen)
}화면을 기준으로 배치
go
// Top-left corner
func positionTopLeft(window *application.WebviewWindow, screen *Screen) {
window.SetPosition(screen.X+10, screen.Y+10)
}
// Top-right corner
func positionTopRight(window *application.WebviewWindow, screen *Screen) {
windowWidth, _ := window.Size()
window.SetPosition(screen.X+screen.Size.Width-windowWidth-10, screen.Y+10)
}
// Bottom-right corner
func positionBottomRight(window *application.WebviewWindow, screen *Screen) {
windowWidth, windowHeight := window.Size()
window.SetPosition(
screen.X+screen.Size.Width-windowWidth-10,
screen.Y+screen.Size.Height-windowHeight-10,
)
}다중 모니터 지원
여러 모니터 감지
go
func hasMultipleMonitors() bool {
return len(app.Screen.GetAll()) > 1
}
func getMonitorCount() int {
return len(app.Screen.GetAll())
}모든 모니터 나열
go
func listMonitors() {
screens := app.Screen.GetAll()
fmt.Printf("Found %d monitor(s):\n", len(screens))
for i, screen := range screens {
primary := ""
if screen.IsPrimary {
primary = " (Primary)"
}
fmt.Printf("%d. %s%s\n", i+1, screen.Name, primary)
fmt.Printf(" Resolution: %dx%d\n", screen.Size.Width, screen.Size.Height)
fmt.Printf(" Position: %d,%d\n", screen.X, screen.Y)
fmt.Printf(" Scale: %.2fx\n", screen.ScaleFactor)
}
}모니터 선택
go
func chooseMonitor() (*Screen, error) {
screens := app.Screen.GetAll()
if len(screens) == 1 {
return screens[0], nil
}
// Show dialog to choose
var options []string
for i, screen := range screens {
primary := ""
if screen.IsPrimary {
primary = " (Primary)"
}
options = append(options,
fmt.Sprintf("%d. %s%s - %dx%d",
i+1, screen.Name, primary, screen.Size.Width, screen.Size.Height))
}
// Use dialog to select
// (Implementation depends on your dialog system)
return screens[0], nil
}전체 예제
다중 모니터 창 관리자
go
type MultiMonitorManager struct {
app *application.App
windows map[int]*application.WebviewWindow
}
func NewMultiMonitorManager(app *application.App) *MultiMonitorManager {
return &MultiMonitorManager{
app: app,
windows: make(map[int]*application.WebviewWindow),
}
}
func (m *MultiMonitorManager) CreateWindowOnScreen(screenIndex int) error {
screens := m.app.Screen.GetAll()
if screenIndex < 0 || screenIndex >= len(screens) {
return errors.New("invalid screen index")
}
screen := screens[screenIndex]
// Create window
window := m.app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: fmt.Sprintf("Window on %s", screen.Name),
Width: 800,
Height: 600,
})
// Centre on screen
x := screen.X + (screen.Size.Width-800)/2
y := screen.Y + (screen.Size.Height-600)/2
window.SetPosition(x, y)
window.Show()
m.windows[screenIndex] = window
return nil
}
func (m *MultiMonitorManager) CreateWindowOnEachScreen() {
screens := m.app.Screen.GetAll()
for i := range screens {
m.CreateWindowOnScreen(i)
}
}화면 변경 감지
go
type ScreenMonitor struct {
app *application.App
lastScreens []*Screen
changeHandler func([]*Screen)
}
func NewScreenMonitor(app *application.App) *ScreenMonitor {
return &ScreenMonitor{
app: app,
lastScreens: app.Screen.GetAll(),
}
}
func (sm *ScreenMonitor) OnScreenChange(handler func([]*Screen)) {
sm.changeHandler = handler
}
func (sm *ScreenMonitor) Start() {
ticker := time.NewTicker(2 * time.Second)
go func() {
for range ticker.C {
sm.checkScreens()
}
}()
}
func (sm *ScreenMonitor) checkScreens() {
current := sm.app.Screen.GetAll()
if len(current) != len(sm.lastScreens) {
sm.lastScreens = current
if sm.changeHandler != nil {
sm.changeHandler(current)
}
}
}DPI를 고려한 창 크기 조정
go
func createDPIAwareWindow(screen *Screen) *application.WebviewWindow {
// Base size at 1.0 scale
baseWidth := 800
baseHeight := 600
// Adjust for DPI
width := int(float32(baseWidth) * screen.ScaleFactor)
height := int(float32(baseHeight) * screen.ScaleFactor)
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Title: "DPI-Aware Window",
Width: width,
Height: height,
})
// Centre on screen
x := screen.X + (screen.Size.Width-width)/2
y := screen.Y + (screen.Size.Height-height)/2
window.SetPosition(x, y)
return window
}화면 레이아웃 시각화 도구
go
func visualiseScreenLayout() string {
screens := app.Screen.GetAll()
var layout strings.Builder
layout.WriteString("Screen Layout:\n\n")
for i, screen := range screens {
primary := ""
if screen.IsPrimary {
primary = " [PRIMARY]"
}
layout.WriteString(fmt.Sprintf("Screen %d: %s%s\n", i+1, screen.Name, primary))
layout.WriteString(fmt.Sprintf(" Position: (%d, %d)\n", screen.X, screen.Y))
layout.WriteString(fmt.Sprintf(" Size: %dx%d\n", screen.Size.Width, screen.Size.Height))
layout.WriteString(fmt.Sprintf(" Scale: %.2fx\n", screen.ScaleFactor))
layout.WriteString(fmt.Sprintf(" Physical: %dx%d\n",
int(float32(screen.Size.Width)*screen.ScaleFactor),
int(float32(screen.Size.Height)*screen.ScaleFactor)))
layout.WriteString("\n")
}
return layout.String()
}권장 사례
✅ 권장 사항
- 화면 수 확인 - 단일 모니터와 다중 모니터를 모두 처리합니다
- 논리 픽셀 사용 - Wails가 DPI를 자동으로 처리합니다
- 창을 중앙에 배치 - 고정 위치보다 더 나은 사용자 경험을 제공합니다
- 위치 검증 - 창이 보이는지 확인합니다
- 화면 변경 처리 - 모니터가 추가되거나 제거될 수 있습니다
- 서로 다른 DPI에서 테스트 - 100%, 125%, 150%, 200%
❌ 금지 사항
- 위치를 하드코딩하지 않기 - 화면 크기를 사용합니다
- 주 화면만 있다고 가정하지 않기 - 사용자에게 여러 모니터가 있을 수 있습니다
- 배율을 무시하지 않기 - DPI 인식에 중요합니다
- 화면 밖에 배치하지 않기 - 좌표를 검증합니다
- 화면 변경을 잊지 않기 - 노트북은 도킹하거나 도킹을 해제할 수 있습니다
- 물리 픽셀을 사용하지 않기 - 논리 픽셀을 사용합니다
플랫폼별 차이
macOS
- Retina 디스플레이(2배 배율)
- 다중 디스플레이가 일반적임
- 좌표계: 왼쪽 아래가 (0,0)
- Spaces(가상 데스크톱)가 배치에 영향을 줌
Windows
- 다양한 DPI 배율(100%, 125%, 150%, 200%)
- 다중 디스플레이가 일반적임
- 좌표계: 왼쪽 위가 (0,0)
- 모니터별 DPI 인식
Linux
- 데스크톱 환경에 따라 다름
- X11과 Wayland의 차이
- DPI 배율 지원이 환경에 따라 다름
- 다중 디스플레이 지원
다음 단계
창
창 관리에 대해 알아보세요.
창 옵션
창 모양을 구성하세요.
여러 창
다중 창 패턴을 알아보세요.
바인딩
JavaScript에서 Go 함수를 호출하세요.