Friday, February 28, 2014

치즈에 붙은 테이프를 떼고 있으면

차라리 사은품을 주지 말라고 하고 싶다.

아오...


우유 등 1+1/1+2 상품도 마찬가지.

Tuesday, February 25, 2014

Saturday, February 8, 2014

ListView 아이템을 Drag and Drop으로 순서 바꾸기 Reorder ListViewItem

놀랍게도 ListView 아이템은 드래그앤드랍이 기본으로는 안 되는데, 더 놀라운 것은 이것이 버그라는 것이다. (오작동뿐 아니라 코드를 빠뜨려서 작동 안 하는 것도 버그이긴 하지...) 1)
http://support.microsoft.com/kb/822483/en-us


위 링크에서 제공하는 코드를 적당히 붙이는 것만으로도 drag & drop으로 순서를 변경하는 작업이 잘 된다.

단, ListViewItem.Name은 보존되지 않는다. 이러면 ListView.Items.RemoveByKey(string=Name)를 할 수 없게 된다.

이는 아마 ListView.Items 내에서의 순서 이동은, 실제로는 ListViewItem 객체의 복사(Clone()이 호출된다) 후 원본 ListViewItem 객체 삭제이므로, container 내에 같은 Name의 객체를 두 개 이상 가질 수 없기 때문일 것이다.
그래서 다음과 같이 Name을 재지정해야 한다.
        void listView1_DragDrop(object sender, DragEventArgs e)

        {
                //(전략)
                ListViewItem insertItem = (ListViewItem)dragItem.Clone();
                listView1.Items.Insert(itemIndex, insertItem);
                listView1.Items.Remove(dragItem);
             
                //dragItem을 Remove한 뒤 다시 설정해 줌:
                insertItem.Name = dragItem.Name; 

            }

물론 처음부터 Name을 쓰지 않고 있었다면 해 주지 않아도 된다.

참고로, 위 코드를 ListView에 적용하기 위해 핸들러를 만들어야 하는 이벤트는 ItemDrag, DragEnter, DragDrop의 3개이다.
IDE 디자이너의 '속성' 창에서 찾을 수 있긴 한데,
DragDrop, DragEnter는 "끌어서 놓기" 분류에,
ItemDrag는 "작업" 분류에 들어가 있어 찾기가 매우 어렵다.

그냥 코드로 치는 게 (적절히 tab하면 핸들러도 만들어 주니까) 편하다.


-----------------------
1) 의도된 사항(design)이라고 답변한 것이다.

Sunday, February 2, 2014

Age of Empires: Rise of Rome 고해상도로 플레이하기

Voobly라는 데를 발견했다!

설치하고, 가입하고 적당한 로비에 들어가서 방을 만든 후 플레이하면 된다.

 http://www.voobly.com/games/view/Age-of-Empires

여기는 Age of Empires 로비이다.

기본적으로 멀티플레이 모드가 실행되지만
싱글 플레이도 가능하다.

http://www.voobly.com/pages/view/310

따라서 캠페인도 고해상도로 플레이 가능.

Rise of Rome 로비는 따로 있으니 주의. Rise of Rome으로 해야 EMPIRESX.EXE가 실행된다.

Monday, January 27, 2014

BinaryWriter로 String을 썼는데 앞에 쓰레기값이 붙음 어떻게 해야 함?

그거 문자열 길이임 ㅋㅋㅋ

System.IO.BinaryWriter(System.IO.Stream)
"제공된 스트림을 기반으로 UTF-8을 문자열의 인코딩으로 사용하여 BinaryWriter 클래스의 새 인스턴스를 초기화합니다."

void BinaryWriter.Write(string)
"BinaryWriter의 현재 인코딩으로 된 이 스트림에 문자열의 길이가 맨 앞에 나오는 문자열을 쓴 다음 사용된 인코딩과 스트림에 쓰여지는 특정 문자의 길이만큼 스트림의 현재 위치를 앞으로 이동합니다"

그럼 이렇게 쓴 문자열을 읽을 때는 어떻게 해야 할까?
일단 integer를 하나 읽고, 거기서... 그럴 리가 없고

그냥 읽으면 된다.
BinaryReader.ReadString()은 문자열의 길이가 맨 앞에 오는 문자열을 읽게 되어 있다.

VS2010의 이 함수 설명은 해석이 괴상한데, 사실 원문도 좀 이상하긴 하다.

현재 스트림에서 문자열을 읽습니다. 한 번에 7비트 정수로 인코딩된 문자열 길이는 해당 문자열 앞에 옵니다.

원문은 이거다:
Reads a string from the current stream. The string is prefixed with the length, encoded as an integer seven bits at a time.
String이 length로 prefixed되어 있다는 중요한 사실을 먼저 말하는 게 당연하다.

위 번역은 일단 쉼표(,)로 구분된 문장을 잘못 번역했다.
(그) 문자열은 (문자열) 길이가 (맨) 앞에 오며, 이것(문자열 길이를 나타내는 정수)은 한 번에 7비트 정수로 인코딩되어 있습니다.

한 번에 7비트 정수로 인코딩(encoded as an integer seven bits at a time)은 도대체 무슨 소리일까?
같은 궁금증을 가진 사람이 역시 있었다:
답변자는 BinaryReader의 소스코드까지 따라가 보았다. 존경한다.
요약하면, 문자열 길이는 int의 배열로 저장되는 게 아니라, 8비트(=1바이트) 중 최상위 1비트를 다음 바이트가 필요한 지 여부를 나타내는 데 씀으로써 정수 크기에 따라 필요한 바이트 수에 맞게 알아서 잘(...) 쓴다는 것이다.
예를 들어 127까지는 7비트 이내니까 그냥 쓰고, 그보다 큰 숫자는 앞에 표시해서(아마도 0이 아니라 1로 세팅하거나 그런 거겠지) 다음 바이트도 (문자열이 아니라 문자열 길이를 나타내는) 정수로 읽게 하는 것이다. - 대충 이해한 거라 틀릴 수도 있지만 대략의 내용은 맞을 것이다.

그냥 7bitEncoding을 이용해 인코딩되어 있다(encoded by 7bitEncoding)라고 했으면 7bitEncoding이라는 게 있나 보다 하고 넘어갔을 텐데 encoded as an integer seven bits at a time이라는 문장이 오해를 불렀다.
전문 용어를 전문 용어가 아닌 척하고 쓰는 건 나쁜 글쓰기 습관이다. 특히나 개념에 대한 검색을 어렵게 한다는 점에서 그렇다. Encode ... ~ bits at a time이 업계의 관용구인가 알아보려고 해도 알 수가 없잖아?

Friday, January 24, 2014

파워포인트PowerPoint 2007 Two-Page View 한 화면에 두 페이지 보기

진짜 되는 건 아니고 흉내낼 수는 있다.


새 창을 누르면 아무 것도 안 변한 것 같지만 PowerPoint 창 제목이 바뀌어 있다:


프레젠테이션1:2에서 :2 부분이 같은 파일을 연 창 여러 개 중 2번째라는 뜻이다('프레젠테이션1'이 파일 이름이다. 저장하기 전이라 그렇다. 저장한 파일 이름이 name.pptx면 name.pptx:2라고 나왔을 것이다).

작업표시줄을 보면 창이 두개 열린 것을 확인할 수 있다.
여기서 (작업표시줄 단추를 눌러) 다른 창을 고르면 역시 변한 게 없다. 어쩌란 말인가?
▶ 이건 PowerPoint 프로그램의 인스턴스를 두 개 이상 띄울 수 없게 해 놓았기 때문이다(정확히는 꼭 그런 건 아니지만 창의 관점에서 그렇다는 것이다.). 여기서 의문이 생긴다. 한 가지 파일을 여러 여러 뷰(view)에서 보고자 한다면 여러 창을 동시에 볼 수 있어야 할 게 아닌가? 도대체 새 창 버튼은 왜 만든 것인가?

해결책은 모두 정렬 버튼에 있다.

모두 정렬을 누르면 다음과 같이 two-page view 짝퉁을 구현할 수 있다(물론 창을 더 열어 3-page view도 가능하다.).

그러니까, 처음 '새 창'을 만들었을 때까지는 non-MDI 모드로 계속 동작하고, 모두 정렬 또는 계단식 버튼을 누르면 그제서야 MDI 모드로 동작하는 것이다. 반면 Excel은 처음부터 MDI 모드이기 때문에 새 창을 만들면, 만든 창이 바로 보이므로 창이 어디 갔나 찾지 않는다.

참고로 최대화된 창의 제목표시줄을 잡아당겨 이전 창으로 복귀*하게 할 수 있는데, 이것이 Word, PowerPoint에서는 되지만 Excel에서는 안 된다. 이 또한 Microsoft의 멋짐이라. (끌어당겨서 최대화는 되는 것도 멋짐.)


------------------------
* 최대화되지 않은 창.

Thursday, January 23, 2014

오늘의 골때리는 js 현상: alert 창을 닫아도 클릭 이벤트가 계속 trigger되어 alert가 무한히 나옴

텍스트박스에서 엔터를 치면 자동으로 입력되게 하려고 keyup 이벤트 핸들러를 등록했다.
잘 동작하는 듯했는데  alert창을 닫아도 닫아도 계속 열리는 것이다.
크롬이어서 다행이지 IE였으면 무한히 열렸을 거야...스페이스바로 눌러보길 잘했지*

$('<input/>', { type: "text", id: "myInput" })
.appendTo(myForm)
.keyup(function (event) {
if (event.keyCode == 13) {  // 13=ENTER
// $(this).blur();
$("#myButton").click();
});
$('<button/>', { type: "button", text: "입력", id: "myButton" })
                .appendTo(myForm)
                .click(myButton_Click);

function myButton_Click() {
   alert("이거 무한 반복됨");
}


해결책: 저 코드의 주석을 해제하여 $(this).blur()로 포커스를 강제 해제하면 된다. alert 창이 닫힌 후 focus가 돌아오지 않는다는 게 문제지만 그건 나중에 해결하고.

아무튼 javascript는 콜백함수에서 입력한 게 콜백함수를 호출한 쪽에도 영향을 미치는 병맛나는신박한 언어다. 아니, jQuery의 문제인가? 뭔가 event.preventDefault() 같은 게 있는 거 같은데 해도 안 되고 그건 나중에 알아보기로.


*사실은 ok 버튼을 엔터키로 누를 때만 그렇다. 마우스로 클릭하거나 스페이스바로 확인하면 그러지 않는다(이벤트가 발생하지 않으므로 당연하다). 

iOS26 거울 아이콘

오래 전에 iPhone을 기울이면(tilt) 아이콘이 살짝 움직이는 업데이트가 있었다. Motion toggle이라고 한다... (Reddit 포스트조차 5년 전이다) https://www.reddit.com/r/jailbreak/comments/gg...