글 목록 보기

Lyn
조회 수 106 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

WPF 에는 표처럼 오브젝트를 배치할 수 있는 Grid 라는 Layout 컨테이너가 존재한다

 

그런데 이 컨테이너는 Layout 만 잡아 줄 뿐 표처럼 선을 그려주는 기능은 없... 진 않지만 내장되어 있는 ShowGridLines 는 사실상 UI 디버깅 용도 외에는 쓰기 힘들정도로 심각하게 기능이 구리다.

 

그래서 유명하신 정성태님이 아래와 같은 글을 쓰셧다

 

WPF - Grid 컨트롤의 ShowGridLine 개선

 

윗 링크의 글을 보면 아래와 같은 부분이 있다

 

"생각 자체는 그리 어렵지 않습니다. 예를 들어, 가로선을 그을 때(Row별로) 컬럼 단위만큼 그리며 진행하다가 다음번 그려야 될 곳이 RowSpan으로 되어 있으면 그 구획은 긋지 말고 건너뛰면 됩니다. 세로선도 마찬가지겠지요."

 

그리고 해당 컨트롤을 구현한 솔루션이 링크되어 있는데... 실제로는 구현이 반대로 되어 있다. Element 를 뒤져 가며 Span 된 부분을 건너뛰는 것이 아니라 Span 이 아닌 부분을 그리는 식으로. 사실 이렇게 하더라도 저 위 샘플에선 전혀 문제가 없이 나오는데... 문제는 저 Grid에 어떤 Element 도 없는 "빈칸" 이 존재할 경우 그 부분은 아예 Border 가 그려지지 않는다는 것이다...

 

그래서 위에 인용한 글 대로 Skip 하는 식으로 변형을 해서 쓰기로 했고, 그 코드를 공개한다

 

public class BorderGrid : Grid
{
    public BorderGrid() : base()
    {

    }

    public Thickness CellPadding
    {
        get
        {
            return (Thickness)this.GetValue(CellPaddingProperty);
        }
        set
        {
            this.SetValue(CellPaddingProperty, value);
        }
    }

    public static readonly DependencyProperty CellPaddingProperty =
        DependencyProperty.Register("CellPadding", typeof(Thickness), typeof(BorderGrid),
            new FrameworkPropertyMetadata(new Thickness(0.0, 0.0, 0.0, 0.0), FrameworkPropertyMetadataOptions.AffectsArrange,
            OnCellPaddingChanged)
        );

    static void OnCellPaddingChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
    {
        BorderGrid grid = (dependencyObject as BorderGrid);
        foreach (UIElement uiElement in grid.Children)
        {
            ApplyMargin(grid, uiElement);
        }
    }

    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        FrameworkElement childElement = visualAdded as FrameworkElement;
        ApplyMargin(this, childElement);

        base.OnVisualChildrenChanged(visualAdded, visualRemoved);
    }

    public static void ApplyMargin(BorderGrid PaddingGrid, UIElement element)
    {
        FrameworkElement childElement = element as FrameworkElement;
        Thickness cellPadding = PaddingGrid.CellPadding;

        BorderGrid childPaddingGrid = element as BorderGrid;
        if (childPaddingGrid != null)
        {
            childPaddingGrid.CellPadding = cellPadding;
        }
        else
        {
            if (childElement != null)
            {
                childElement.Margin = cellPadding;
            }
        }
    }

    Pen line = new Pen(Brushes.Black, 2);
    protected override void OnRender(System.Windows.Media.DrawingContext dc)
    {
        base.OnRender(dc);

        BorderGrid customGrid = this.Parent as BorderGrid;
        if (customGrid == null)
        {
            dc.DrawRectangle(null, line, new Rect(0, 0, this.ActualWidth, this.ActualHeight));
        }

        double linePoint = 0;
        double posFrom = 0.0;
        double posTo = 0.0;

        int rowCount = Math.Max(this.RowDefinitions.Count, 1);
        int columnCount = Math.Max(this.ColumnDefinitions.Count, 1);

        bool[,] rowCellIgnoreStatus;
        bool[,] columnCellIgnoreStatus;

        GetRowLineCellStatus(rowCount, columnCount, out rowCellIgnoreStatus, out columnCellIgnoreStatus);

        if (this.ColumnDefinitions.Count != 0)
        {
            for (int row = 0; row < rowCount - 1; row++)
            {
                var r = this.RowDefinitions[row];

                linePoint += r.ActualHeight;
                for (int column = 0; column < columnCount; column++)
                {
                    bool ignoreLine = rowCellIgnoreStatus[row + 1, column];
                    posTo += this.ColumnDefinitions[column].ActualWidth;

                    if (ignoreLine == false)
                    {
                        dc.DrawLine(line, new Point(posFrom, linePoint), new Point(posTo, linePoint));
                    }

                    posFrom = posTo;
                }

                posFrom = 0.0;
                posTo = 0.0;
            }
        }

        linePoint = 0;
        posFrom = 0.0;
        posTo = 0.0;

        if (this.RowDefinitions.Count != 0)
        {
            for (int column = 0; column < columnCount - 1; column++)
            {
                var r = this.ColumnDefinitions[column];

                linePoint += r.ActualWidth;
                for (int row = 0; row < rowCount; row++)
                {
                    bool ignoreLine = columnCellIgnoreStatus[row, column + 1];
                    posTo += this.RowDefinitions[row].ActualHeight;

                    if (ignoreLine == false)
                    {
                        dc.DrawLine(line, new Point(linePoint, posFrom), new Point(linePoint, posTo));
                    }

                    posFrom = posTo;
                }

                posTo = 0.0;
                posFrom = 0.0;
            }
        }
    }

    private void GetRowLineCellStatus(int rowCount, int columnCount, out bool[,] rowCellIgnoreStatus, out bool[,] columnCellIgnoreStatus)
    {
        rowCellIgnoreStatus = new bool[rowCount, columnCount];
        columnCellIgnoreStatus = new bool[rowCount, columnCount];

        foreach (UIElement element in this.Children)
        {
            int row = Grid.GetRow(element);
            int column = Grid.GetColumn(element);

            int spanCount = Grid.GetColumnSpan(element);

            for (int span = 1; span < spanCount; span++)
            {
                try
                {
                    columnCellIgnoreStatus[row, column + span] = true;
                }
                catch (Exception)
                {
                    //
                }
            }

            spanCount = Grid.GetRowSpan(element);
            for (int span = 1; span < spanCount; span++)
            {
                rowCellIgnoreStatus[row + span, column] = true;
            }
        }
    }
}

 

TAG •
?

?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

Decorator border = VisualTreeHelper.GetChild(listViewName 0) as Decorator;
ScrollViewer scrollViewer = border.Child as ScrollViewer;
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 1);

 

ListView 의 ScrollBar 는 저렇게 2단계를 거쳐서찾아 올 수 있고, ScrollToVerticalOffset를 이용 하여 Item 단위로 스크롤을 조절할 수 있다.

TAG •
?

Lyn
조회 수 195 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

얼마전 .net 4.7이 출시되어 시간난김에 구경하는데

 

DirectX Dependency

The .NET Framework 4.7 now uses DirectX 11 components for WPF. These components are available as part of the operating system in recent versions of Windows including Windows 10, Windows Server 2016, Windows 8.1, and Windows Server 2012 R2.

 

같은 내용이 있네요

 

DX11은 Windows 7 에서도 지원 하는데, 7 지원을 빼버린거 보니 슬슬 끝물인가봅니다

TAG •
?

Lyn
조회 수 940 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

C++ Korea 에서 질문을 하나 받았습니다.

 

왜 아래 코드를 출력하면 결과가 1인가요? 라는 질문이었지요

struct Some
{
public:
    void func()
    {
        int i;
        i = 100;
        cout << i << endl;
    }
};

int main()
{
    cout << "Value : " << &Some::func << endl;
}

 

 

이걸 이해하려면 C++ 의 Type System 을 이해 하면 간단합니다.

 

첫째 :  &Some::func 는 Some의 Member function 으로서 void (Some::*foo)(void) 라는 Member Function Pointer Type을 가집니다.

 

둘째 : cout 은 stdout 을 대상으로 하는 출력 객체 이며 << 연산자에 대해 여러가지 type 으로 overloading 되어 있습니다.
실제 코드를 보면 bool, ushort ,short, int, uint, long, ulong, longlong, ulonglong, float, double, long double, void*, char, whcar_t, char* wchar_t* 에 대해 overloading 되어 있는것을 확인 할 수 있습니다(visual c++ 기준 ostream 헤더). string / wstring 에 대한 overloading 은 ostream 측에서 제공하는 것이 아니라 string 쪽에서 추가로 지원 하는 것이라 ostream 의 일부라 보기는 어렵습니다.

 

셋째 : overloading 된 함수를 호출 할 경우 완전히 매칭 되는 타입의 함수를 호출합니다.

하지만 내가 방금 만든 Class 의 MemberFunction Type 이 미리 준비 되어 있을리가 없겠죠

 

넷째 : 완전히 매칭되는 함수가 없을 경우 변환 가능한 가장 "적절한" type 의 함수로 호출합니다.
 

자 그럼 이제 어떤 type으로 캐스팅이 가능하냐를 봐야 하는데... 일단 정수형과 부동소수점은 딱 봐도 안될 것 같습니다.

문자 / 문자열포인터 역시 가지고 있는것이 string 일리가 없으므로 그렇게 암시적으로 캐스팅 하면 AccessVoliation 의 지름길일 겁니다.

그럼 void* 는 어떨까요? 임의의 pointer를 가지는 type 이지만 Member Function Pointer 만큼은 예외입니다.

void*는 일반적인 포인터 사이즈 이지만 Member Function Pointer 는 그렇지 않습니다. 상속을 어떤 구조로 어떻게 받느냐에 따라 크기가 변하지요

간단한 예로 

 

cout << sizeof(&iostream::flush);

 

를 실행시켜 보면 VC++ x64 기준 16Byte가 나오는 것을 볼 수 있습니다. 경우에 따라 크기가 달라지는 이 시스템은 C++만의 독특한 구현이며 이것이 std::function 이 나오기 전까지 임의의 member function 을 가지는 변수를 선언 할 수 없었던 이유이기도 합니다. 그래서 void* 도 아웃이네요

 

자 그럼 bool 하나만 남았는데... 그럼 Member Function Pointer 가 bool로 캐스팅 될 수 있을까요? 정답은 가능하다 입니다.

어렵게 생각 하실 것 없습니다. 그동안 Function Pointer 를 다루셧던 분들은 아래와 같은 코드를 보거나 혹은 사용해 보셨을 것입니다

 

if(ptr) {

   //dosomething

}

 

이런식으로 ptr 이 nullptr 이 아닌지 체크 하여 사용하는 코드가 가능햇죠. 이 말은 반대로 말하면 ptr이 if 의 조건 이 될 수 있다는 것이며 if 의 조건이 될 수 있다는 말은 C++ 에서는 bool 로 캐스팅 가능 하다는 이야기가 됩니다. 

C++ 표준 라이브러리의 많은 식도 이런식으로 bool 캐스팅을 가능하게 하여 구현했는데 shared_ptr<T> 같은 포인터를 랩핑하는 객체가 대표적입니다. 특정 객체의 사용 가능 여부를 bool 로 캐스팅 하여 체크한다는 아주 단순한 방법을 이용 할 수 있게 하는거지요. 이런 기법을 C++ Safe Bool Idiom 이라고 부릅니다. Classic C++ 에서는 구현이 상당히 복잡했지만 C++11 에 와서는 특히 간단히 구현할 수 있게 되어 더욱 많이 쓰게 되는 방법이 되었지요.

 

자 그럼 Member Function Pointer 가 bool로 캐스팅이 될 수 있다는것은 알았습니다. 그리고 당연히 변수가 아니라 존재하는 Function 의 Pointer를 가져온 것이므로 nullptr 이 아닐것이 확실합니다. 결과적으로 cout << true 의 결과물인 1이 출력 되는 거겠구요.

 

그럼 위 코드에 간단한 함수를 하나 추가 해서 정말 그러한지 테스트를 해 봅시다

 

void foo(void* v)
{
    cout << "ptr";
}

void foo(bool v)
{
    cout << "bool";
}

void foo(int v)
{
    cout << "int";
}

void foo(double v)
{
    cout << "double";
}

int main()
{
    foo(&Some::func);
}

 

결과물은 당연히 bool이 나오게 됩니다.

 

참고자료 : C++ Idioms/Safe bool https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool

TAG •
?

Lyn
조회 수 1360 추천 수 0 댓글 0
Atachment
첨부 '2'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

정말 오랫만에 로우레벨 관련 질문을 받았습니다...

바로 아래 코드에서

 

#include <smmintrin.h>

int main()
{
    __m128i m_128i;
    m_128i.m128i_i16[0] = 0;

    for (int i = 0; i < 15; i++)
    {
        auto a = _mm_extract_epi8(m_128i, i); // <-- 컴파일 에러
    }
}

 

error C2057: expected constant expression 에러가 발생 한다는 얘기입니다.

 

_mm_extract_epi8 의 prototype 을 확인 해 보면 extern int   _mm_extract_epi8 (__m128i /* src */, const int /* index */); 입니다. 일반적으론 변수 -> const 로의 변환은 자유로우므로 문제가 없어야 하는데... 오류가 나죠.

 

원인은 간단한데 _mm_extract_epi8 는 C++의 "함수" 가 아니라, 기계어와 매칭되는 Intrinsics 입니다. 저게 선언되어있는 헤더가 smminstrin.h 라는 것에서도 알 수 있지요. 해당명령어는 intel 명령어이니 intel 사이트에서 한번 해당 내용을 검색 해 봅시다

 

inst01.PNG

 

 

몇가지 정보가 나오네요. 해당 Intrinsics 에 대응되는 어셈블리는 pextrb r32, xmm, imm 이고, SSE4.1 지원이 필요하며, Latency 는 CPU 종류에 따라 2~3 클럭이네요.

 

여기는 Visual Studio 에 들어있는 헤더와 달리 각 파라메터에 이름이 붙어있습니다. a, 와 imm8 이네요.
그럼 imm8 은 뭐냐가 중요해지는데, 이 imm은 이름만 보면 무슨 레지스터 비슷한걸로 착각 할 수도 있는데, 실제로는 Immediate value 의 약자입니다.
한자로는 즉치값(즉시 계산되는 값) 이라고도 하는 것 같은데 C++ 프로그래머 입장에서 보자면 컴파일타임에 계산하여 결정이 가능한 상수(const) 를 이야기 합니다. 8은 뭐냐구요? 걍 bit 수 입니다. 저 값은 8bit 범위에서 작동한다는 거죠. 즉 imm8 을 풀어서 써보면 8-bit immediate value 라고 할 수 있겠습니다.

 

그럼 결론을 내보자면. Intrinsics 를 호출 할때는, C++의 호출/캐스팅 규칙 보다 CPU 명령어의 제약사항이 우선하며, _mm_extract_epi8 의 2번째 argument는  Immediate value 일 것을 요구하므로 변수를 사용할 수 없습니다.

 

기왕 하는김에 하나 더 해보자면, imm8 이라고 되어있긴 하지만, 128bit 변수를 8bit 단위로 쪼개서 값을 읽는 명령이므로, 실제 imm8의 사용 범위는 0~15 일 것입니다. 그런데 만약 그 이상의 값(ex : 16) 을 넣으면 어떻게 될까요?

 

 inst02.PNG

 

다행히도 컴파일러는 해당 명령어의 허용 범위를 알고 있으므로 

warning C4556: value of intrinsic immediate argument '16' is out of range '0 - 15' warning 을 띄워 줍니다.

 

TAG •
?

Lyn
조회 수 1370 추천 수 0 댓글 0
Atachment
첨부 '1'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

afree.png

 

TAG •
?

Lyn
조회 수 1728 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

add compile option flag /d2Zi+

 

맨날 까먹어서 저장용으로

?

Lyn
조회 수 3876 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

어떨라나요. 좀 빨라졌으려나요?

?

Lyn
조회 수 1711 추천 수 0 댓글 0
Atachment
첨부 '1'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

게임 결제 한번 하기 힘드네요....

 

Untitled.png

 

TAG •
?

2016.09.07 03:31

where check http/2 online

Lyn
조회 수 1665 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

https://tools.keycdn.com/http2-test

?

Board Pagination Prev 1 2 3 4 5 6 7 8 9 10 ... 13 Next
/ 13