반응형

Content Size Fitter가 사용된 오브젝트는 설정에 따라 Rect Transform의 Width, Height 필드가 잠기고 Some values driven by ContentSizeFitter라는 메세지가 표시된다.

 

Content Size Filter

 

Rect Transform

 

그리고 이 Rect Transform의 sizeDelta(Width, Height 정보가 있는 Vector2 구조체)를 스크립트에서 확인해 보면 (0, 0)을 반환하는 경우가 발생할 수 있다. 아래 코드를 참고해서 해결하자.

 

void Start()
{   
    RectTransform[] crt = GetComponentsInChildren<RectTransform>();
    // 자식 오브젝트와 같은 컴포넌트를 가진 상태에서 GetComponentInChildren<>()을 사용해 그
    // 컴포넌트를 가져오면 항상 자신의 컴포넌트가 리턴된다. 또, GetComponenetsInChildren<>()
    // 사용시 0번 인덱스도 자신이 된다.

    LayoutRebuilder.ForceRebuildLayoutImmediate(crt[1]);
    //Canvas.ForceUpdateCanvases();
    // LayoutRebuilder.ForceRebuildLayoutImmediate()대신 위 함수를 사용해도 된다.
    // 하지만 비효율적.

    Vector2 size = crt[1].sizeDelta;
    //Vector2 size = new Vector2(crt[1].rect.width, crt[1].rect.height);
    
    Debug.Log(crt[1]);
    Debug.Log(size);

    SpriteRenderer sr = GetComponent<SpriteRenderer>();
    sr.size = size;
    // Sprite Renderer 사이즈를 자식 오브젝트 Rect Transform 사이즈로 설정한다.
}

 

부모 오브젝트에 Rect Transform, Sprite Renderer 가 있는 상태에서 위 코드가 포함된 스크립트를 추가했다. 자식 오브젝트에도 Rect Transform이 있고 Content Size Fitter가 추가되어 있다.

sizeDelta 정보에 접근하기 전, ForceRebuildLayoutImmediate()(또는 ForceUpdateCanvases()) 를 먼저 실행하지 않으면 Rect Transform에 필요한 계산이 끝나지 않아 부정확한 정보가 넘어올 수 있다.

 

Rect Transform Details

Note that some RectTransform calculations are performed at the end of a frame, just before calculating UI vertices, in order to ensure that they are up to date with all the latest changes performed throughout the frame. This means that they haven't yet been calculated for the first time in the Start callback and first Update callback.
You can work around this by creating a Start() callback and adding Canvas.ForceUpdateCanvases() method to it. This will force Canvas to be updated not at the end of the frame, but when that method is called.

 

반응형
Posted by J-sean
:
반응형

실행중인 모든 프로세스와 현재 포커스를 갖고 있는 프로세스를 조사하고 각 프로세스의 윈도우 사이즈를 구해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Diagnostics;
using System.Runtime.InteropServices;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string className, string windowName);
        // 이 예제에서는 쓰이지 않았지만 Findwindow()는 아래와 같이 사용하면 된다.
        // IntPtr hwnd = FindWindow(className, windowName);
        // windowName = proc.ProcessName;
        // className = proc.MainWindowTitle;
 
        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
 
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();
 
        [DllImport("user32.dll")]
        private static extern int GetWindowRect(IntPtr hWnd, out Rectangle rect);
 
        [DllImport("dwmapi.dll")]
        private static extern int DwmGetWindowAttribute(IntPtr hWnd, int dwAttribute, out Rectangle pvAttribute, int cbAttribute);
        
        public Form1()
        {
            InitializeComponent();
 
            timer1.Interval = 5000// 5초마다 갱신
        }
        
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Process[] processes = Process.GetProcesses();            
            Rectangle rect;
            // GetWindowRect(), DwmGetWindowAttribute()에 의해 rect에는 아래와 같은 값이 들어간다.
            // rect.X = 좌상단 X 좌표
            // rect.Y = 좌상단 T 좌표
            // rect.Width = 우하단 X 좌표 (너비가 아니다)
            // rect.Height = 우하단 Y 좌표 (높이가 아니다)
            int rectangleSize = Marshal.SizeOf(typeof(Rectangle));
            int index;  // Process.GetProcesses()로 조사된 모든 프로세스 중 몇 번째 인지 나타낼 인덱스.
            int row = 0;    // 내용 표시 Y 위치
            string str;
 
            foreach (Process p in processes)
            { 
                // A process has a main window associated with it only if the process has a graphical interface. If the associated process
                // does not have a main window, the MainWindowHandle value is zero. The value is also zero for processes that have been hidden,
                // that is, processes that are not visible in the taskbar. This can be the case for processes that appear as icons in the
                // notification area, at the far right of the taskbar.
                // 테스크 바에 표시되는(보이는) 프로세스만 조사. 윈도우 핸들이 0(IntPtr.Zero)이 아닌 윈도우인데 그렇다고 다 보이는 건 아니다.
                if (p.MainWindowHandle != IntPtr.Zero)
                {
                    index = Array.IndexOf(processes, p); // 비효율적인 배열의 인덱스 가져오기. foreach()말고 for(;;)를 쓰는게 낫다.
                    DwmGetWindowAttribute(p.MainWindowHandle, 9out rect, rectangleSize);
                    // 9 = DWMWA_EXTENDED_FRAME_BOUNDS
                    str = string.Format("[{0}] {1}: ({2}, {3}, {4}, {5})", index, p.ProcessName, rect.X, rect.Y, rect.Width, rect.Height);
                    e.Graphics.DrawString(str, Font, Brushes.Black, 0, row);
                    row += 15;
                }
            }
            
            // 포커스를 갖고 있는 윈도우(Foreground window) 조사
            uint foregroundProcessID = 0;
            IntPtr foregroundHWnd = GetForegroundWindow(); // Get foreground window handle
            uint threadID = GetWindowThreadProcessId(foregroundHWnd, out foregroundProcessID); // Get PID from window handle
            Process foregroundProcess = Process.GetProcessById(Convert.ToInt32(foregroundProcessID)); // Get it as a C# obj.
 
            // 윈도우 사이즈 조사
            DwmGetWindowAttribute(foregroundHWnd, 9out rect, rectangleSize);
            // 9 = DWMWA_EXTENDED_FRAME_BOUNDS            
            str = string.Format("[Foreground] {0}: ({1}, {2}, {3}, {4})", foregroundProcess.ProcessName, rect.X, rect.Y, rect.Width, rect.Height);
            e.Graphics.DrawString(str, Font, Brushes.Black, 0, row);
            row += 30;
 
            // Windows 10 has thin invisible borders on left, right, and bottom, it is used to grip the mouse for resizing.
            // The borders might look like this: 7, 0, 7, 7(left, top, right, bottom)
            // 윈도우 사이즈 조사 시 예전과 같이 GetWindowRect()를 사용하면 보통 7픽셀의 resizing을 위한 테두리가 포함된다.
            e.Graphics.DrawString("[Foreground window with invisible border]", Font, Brushes.Red, 0, row);
            row += 15;
            GetWindowRect(foregroundHWnd, out rect);
            str = string.Format("[Foreground] {0}: ({1}, {2}, {3}, {4})", foregroundProcess.ProcessName, rect.X, rect.Y, rect.Width, rect.Height);
            e.Graphics.DrawString(str, Font, Brushes.Black, 0, row);
        }
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            Invalidate();
        }
    }
}
 

 

소스를 입력하고 실행한다.

 

인덱스를 확인하면 수백개의 프로세스가 실행중임을 알 수 있다.

 

GetWindowRect()로 윈도우 사이즈를 구하면 resizing을 위한 보이지 않는 테두리가 포함 되므로 눈에 보이는 정확한 사이즈는 DwmGetWindowAttribute()로 구하자.

 

반응형
Posted by J-sean
: