C++의 가장 큰 장점이자 단점이라고 하면 대부분의 사람들이 공통으로 꼽는 것이 바로 '포인터의 사용'이다.

C++은 포인터를 이용하여 메모리를 직접 관리하고, 따라서 타 언어에 비해 훨씬 성능이 좋다.


하지만 포인터는 양날의 검이다. 잘 다루면 성능 좋은 프로그램을 만들 수 있지만 메모리 관리를 잘못하는 순간 프로그램이 박살날 수 있다.


 C++ 개발자들은 이런 메모리 관리 문제를 어떻게 해결하면 좋을지 생각하다가 '스마트 포인터'라는 개념을 만들었다.

이것을 이용해 메모리를 할당하면 메모리 관리를 자동으로 해 주는 아주 편리한 도구인 것이다.


 초기 스마트 포인터는 auto_ptr 이라는 예약어를 이용하여 할당할 수 있었다.

auto_ptr로 할당한 메모리는 소유권이라는 것을 가지고 있어, 이를 가리키고 있던 포인터가 사라지면 메모리를 자동으로 해제해 주는 편리함을 제공했다.

하지만 auto_ptr에는 여러가지 문제점이 있었는데, 바로 '소유권 이전'에 관한 문제였다.


 auto_ptr로 생성한 포인터는 다른 포인터에 복사할 경우 소유권을 이전하게 되는데, 복사한 포인터가 사라질 경우 할당된 메모리를 자동으로 해제해버리는 문제가 발생한다.

간단한 예제로 다음과 같은 코드를 돌려보자.


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
#include "stdafx.h"
#include "memory"  
#include "iostream"  
 
class MyClass
{
public:
    int num;
    MyClass()
    {
        std::cout << "Ctor" << std::endl;
    }
 
    ~MyClass()
    {
        std::cout << "Dtor" << std::endl;
    }
};
 
void print_num(std::auto_ptr<MyClass> myClass)
{
    std::cout << myClass->num << std::endl;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    std::auto_ptr<MyClass> myClass(new MyClass);
    myClass->num = 1234;
    std::cout << "print start" << std::endl;
    print_num(myClass);
    std::cout << "print ended" << std::endl;
    std::cout << myClass->num << std::endl;
    return 0;
}
 
cs




 아름답게 박살이 나는 프로그램의 모습을 볼 수 있다.

출력된 것을 보면 알겠지만 print_num 함수 내부의 매개변수로 main의 myClass가 복사되면서 소유권이 이전되었고, print_num 함수가 끝나면서 myClass가 할당된 메모리가 해제되어 main에서 해제된 메모리를 참조하려다 에러가 나는 것이다.


 이런 auto_ptr의 단점을 보완한 것이 shared_ptr이다.

본래 boost 라이브러리에 속해있던 기능이지만 C++11에서 표준으로 포함되었다.

auto_ptr과 달리 shared_ptr은 레퍼런스 카운팅 방식으로 메모리를 관리하기 때문에 해당 인스턴스를 가리키는 포인터가 전부 사라져야 메모리가 해제된다.


auto_ptr을 shared_ptr로 바꾼 코드를 실행시켜보자.


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
#include "stdafx.h"
#include "memory"  
#include "iostream"  
 
class MyClass
{
public:
    int num;
    MyClass()
    {
        std::cout << "Ctor" << std::endl;
    }
 
    ~MyClass()
    {
        std::cout << "Dtor" << std::endl;
    }
};
 
void print_num(std::shared_ptr<MyClass> myClass)
{
    std::cout << myClass->num << std::endl;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    std::shared_ptr<MyClass> myClass(new MyClass);
    myClass->num = 1234;
    std::cout << "print start" << std::endl;
    print_num(myClass);
    std::cout << "print ended" << std::endl;
    std::cout << myClass->num << std::endl;
    return 0;
}
 
cs




 이렇게 정상 작동하는 것을 확인할 수 있다.

이 외에도 스마트 포인터에는 unique_ptr과 weak_ptr이 존재하는데, 이는 다음번에 공부하면서 작성하도록 하겠다.

'Programming' 카테고리의 다른 글

[C++] Boost 설치 & 빌드 환경 구축  (0) 2016.12.20
[C++] unique_ptr, weak_ptr  (0) 2016.12.15
[C++] auto_ptr, shared_ptr  (0) 2016.12.14
[C++] 알아두면 좋은(?) C++ 지식들  (0) 2016.12.13
[C++] 얕은 복사, 깊은 복사, 복사 생성자  (0) 2016.12.13
[C++] std::for_each  (0) 2016.12.12
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요


 이 글은 아직 완성된 글이 아니며, 공부하면서 알게 된 내용들을 바탕으로 짤막한 지식들을 나열해 나갈 것입니다.

잘못된 부분이 있으면 덧글이나 방명록 등으로 알려주시면 감사하겠습니다 :)



1. IO 객체 std::cin/cout/cerr/clog 중 cerr는 un-itbuffered이다.


 흔히 우스갯소리로 printf 디버깅 또는 cout 디버깅이라고 부르는 오류 해결 방식이 오류가 나는 지점 주변에 출력문을 넣어 어디까지 정상적인 값이 출력되었는지를 살펴보는 것이다. C++에서는 출력 방식으로 흔히 std::cout을 사용하는데, 기본적으로 std::cout은 buffered 로 동작하기 때문에 원하는 위치에서 정상적인 출력이 되지 않을 수 있다. 따라서 std::cout으로 로그를 찍기 위해서는 버퍼를 비우는 동작을 추가로 진행해 주어야 하며, 이를 std::endl이 수행한다.


 하지만 그렇게 번거롭게 하지 않더라도 버퍼를 비우는 방법은 한 가지가 더 있는데, 바로 std::cerr를 사용하는 것이다. std::cerr는 디폴트로 un-itbuffered 로 동작한다. un-itbuffered란 '이 연산은 buffered이기는 하지만 출력 이후 바로 버퍼를 비운다'는 것을 의미한다. 따라서 추가로 버퍼를 비우는 행위를 하지 않더라도 정상적인 위치에서 출력이 가능하게 된다.


* buffering이란 효율적인 입/출력을 위해 프로그램에서 일정 크기만큼을 메모리에 임시로 보관하고 있다가 일괄로 처리하는 것을 의미한다.



2. stream의 operator<<, operator>> 는 자기 자신을 반환한다.


  C++을 사용하면서 operator<<를 사용할 때,

1
std::cout << "Hello World!" << std::endl;


 이런 식으로 연속하여 사용해 본 적이 있을 것이다.

이것이 가능한 이유는 앞에서부터 연산을 수행하되, ostream::operator<< 의 리턴 값이 자기 자신이기 때문이다.

즉, 앞의 연산인 std::cout << "Hello World!" 가 먼저 수행되고 자기 자신이 리턴되어 다음 명령도 std::cout << std::endl이 되는 것이다.



3. method와 function은 다르다.


 보통 함수라고 부르는 function은 '이름으로 불려지는 특정 코드의 집합'을 의미한다.  메서드라고 부르는 method는 '특정 객제에 포함된 이름으로 불려지는 특정 코드의 집합'이다. 간단하게 '멤버 함수' == '메서드' 라고 볼 수 있다. 함수가 메서드보다 더 큰 범위라고 할 수 있겠다.



4. std::endl은 함수로 쓸 수 있다.


 std::endl을 보통 '\n'을 출력하는 것과 같다고만 알거나, 조금 더 나가서 버퍼를 flush해준다고 알고 있는 사람들은 많지만 사실 std::endl은 함수로써 사용도 가능하다. 인자로 output stream을 받으며, 사용법은 다음과 같다.

1
std::endl(std::cout);



...계속 추가됩니다.

블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요


 C++에서 가끔 클래스를 복사하게 되는 일이 생긴다.

클래스를 복사하는 방법에는 크게 얕은 복사와 깊은 복사라고 부르는 두 가지의 방법이 있다.

MSDN에서는 전자를 멤버 단위 복사라고 부른다.

클래스 내부의 변수들을 하나하나 똑같이 복사한다고 해서 그렇게 부르는 듯 하다.


 디폴트 생성자와 마찬가지로 멤버 단위 복사 생성자도 따로 복사 생성자를 선언하지 않는 이상 자동으로 생성된다.

따라서 따로 작업을 해주지 않는 이상 컴파일러는 디폴트로 얕은 복사를 수행한다.


 클래스 내에서 포인터를 이용해 메모리 작업을 하지 않는 이상 얕은 복사가 큰 문제가 되는 일은 많지 않을 테지만 만약 클래스 내에서 메모리를 할당하고 소멸자에서 이를 해제하게 하는 등의 작업을 한다면 치명적인 문제가 된다.


다음과 같은 클래스가 있다고 가정해 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
class MyClass {
private:
    char *name;
public:
    MyClass(char*);
    ~MyClass() { delete[] name; }
    void printName() { std::cout << name << std::endl;  }
};
 
MyClass::MyClass(char* newName) {
    name = new char[strlen(newName) + 1];
    strcpy(name, newName);
}
cs


 멤버 변수로 name이라는 char형 포인터를 갖고, 생성자에서 이를 입력받아 할당하며 소멸자에서 해제하는 간단한 클래스이다. 클래스 멤버 함수로 name을 출력해주는 printName을 가지고 있다. 생성자에서 할당하고 소멸자에서 해제하므로 메모리 관리에 아무런 문제가 없어 보이지만, 이를 복사하게 되면 얘기는 달라진다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void printMyClass(MyClass m)
{
    std::cout << "<printMyClass>" << std::endl;
    m.printName();
}
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    MyClass myClass("John");
    std::cout << "<main>" << std::endl;
    myClass.printName();
 
    printMyClass(myClass);
    return 0;
}
cs


 MyClass를 인자로 받고 main에서 인스턴스를 만들어서 이를 인자로 넘겨주면 printMyClass에서는 매개변수로 MyClass를 하나 만들고, 거기에 main에서 생성한 인스턴스를 그대로 복사한다.


얕은 복사가 진행되면서 main에서 생성한 인스턴스 속의 변수도 똑같이 복사되며, 문자열의 주소를 담고 있는 name 변수의 값도 똑같이 복사된다. 즉, 포인터 주소값이 그대로 복사되므로 main의 인스턴스와 같은 주소를 가리키게 된다.


이제 printMyClass 함수가 끝까지 정상적으로 실행되고 함수가 끝나면서 문제가 발생한다.

함수 시작 시 생성된 인스턴스가 할당 해제되면서 소멸자를 호출하고, 메인의 인스턴스의 변수와 함께 가리키고 있는 name 공간도 자동으로 할당이 해제되어 버린다.


이후 main에서 return으로 빠져나가면서 main에서 생성한 인스턴스가 또 할당 해제되고, 소멸자를 한번 더 호출하면서 이미 할당 해제된 공간을 한 번 더 해제하려고 하므로 에러가 발생한다.


 이런 식으로 얕은 복사를 하게 되면 예상치 못한 곳에서 치명적인 에러가 발생할 수 있다.

이런 문제를 해결하기 위해서 보통 class 내부에 복사 생성자를 생성하여 깊은 복사를 진행한다.

깊은 복사를 위해 class에 다음과 같이 복사 생성자를 추가해 주었다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyClass {
private:
    char *name;
public:
    MyClass(char*);
    MyClass(MyClass&);
    ~MyClass() { delete[] name; }
    void printName() { std::cout << name << std::endl;  }
};
 
MyClass::MyClass(char* newName) {
    name = new char[strlen(newName) + 1];
    strcpy(name, newName);
}
 
MyClass::MyClass(MyClass& newClass) {
    name = new char[strlen(newClass.name) + 1];
    strcpy(name, newClass.name);
}
cs


 이제 인스턴스를 복사할 때는 복사 생성자의 소스를 이용하여 깊은 복사를 진행하므로 새로 생성된 인스턴스의 name에도 따로 공간이 할당되고, 값이 똑같이 복사될 것이다. 이 메모리가 해제되더라도 main의 인스턴스가 가리키는 주소와는 연관이 없으므로 아무런 문제가 발생하지 않는다.



블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요

[C++] std::for_each

Programming 2016. 12. 12. 18:13


많은 언어에 존재하는 for-each 구문이다.

C++ 공부도 할 겸 공부한 내용을 정리하면서 이런 글을 자주 작성할 것 같다.


for_each는 <algorithm> 내에 정의되어 있다.

범위를 정해서 루프를 도는 for문과 유사하지만 다른 점은 포인터를 이용해 시퀀스의 변수에 접근한다는 점이다.

따라서 for문처럼 시작과 끝을 정하는 것이 필수적이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stdafx.h"
#include <algorithm>        // for `std::for_each`
#include <vector>            // for `std::vector` 
#include <iostream>            // for `std::cout`
 
void square(int& num) {
    num *= num;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<int> int_vector = { 13579 };
    std::for_each(int_vector.begin(), int_vector.end(), square);
    for (auto num : int_vector)
        std::cout << num << " ";
    std::cout << std::endl;
    return 0;
}
cs


첫 번째 인자로 int형 vector의 시작인 begin()을 주었고, 두 번째 인자로 마지막 변수 다음 값인 end()를 주었다.

각각 시작과 끝을 나타내며, 세 번째 인자에는 함수 객체를 넣어 주어야 한다.


for_each를 통해 참조되는 vector의 각 멤버들을 레퍼런스로 넘겨 이를 제곱하고 있으므로 for_each문이 끝난 이후 모든 멤버들이 제곱되어 있을 것이다.


실제 출력 결과를 확인해 보면 다음과 같이 예상한대로 되어 있는 것을 볼 수 있다.



블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요


Github : https://github.com/skyclad0x7b7/Pacro


 요전부터 개인적으로 사용하려고 만들다가 오픈소스로 내는것도 꽤 괜찮을 것 같다는 생각이 들어 Github에 Pacro라는 이름의 repository를 만들고 개발하기 시작했습니다. GUI 환경은 PyQt4를 이용하여 개발하였고, 자동으로 스크립트를 만들어주는 기능은 pyHook을 이용하여 구현했기 때문에 현재는 윈도우 환경만 지원합니다.


라이센스는 GNU GPL 3.0입니다.


개인적으로 개발하던 프로그램이라 로고도 아이콘도 없습니다.


현재까지는 Click과 Sleep 기능만 개발된 상태이지만 추후 다른 기능들도 추가할 예정입니다.




Pacro GUI는 이런 인터페이스로 동작하며, 반복과 가장 위 고정 기능이 있습니다.



자동으로 스크립트를 만들어주는 MakeScript는 이렇게 작동하며, Start 버튼을 누른 이후 우클릭을 할때까지의 모든 Click을 사이사이에 Sleep과 함께 저장해줍니다.

스크립트는 JSON 형식입니다.


자세한 내용은 Github를 참고하시면 되겠습니다.

'Programming' 카테고리의 다른 글

[C++] 얕은 복사, 깊은 복사, 복사 생성자  (0) 2016.12.13
[C++] std::for_each  (0) 2016.12.12
[Python] Pacro : Python 기반 매크로 프로그램  (4) 2016.11.28
[C++] CreateMutex  (2) 2016.11.22
[PyQt4] 0x07. WebBrowser  (0) 2016.11.21
[PyQt4] 0x06. QYolk III  (0) 2016.11.18
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요

  • python 질문 2017.01.23 10:35  댓글주소  수정/삭제  댓글쓰기

    안녕하세요
    파이썬 코딩하다가 여쭤볼게 있는데요

    두개의 스레드가 있는데
    여기서 다른 스레드에서 다른 스레드의 변수를 접근하려면 어떻게 코딩해야하요,,,?

  • 사용법 2018.07.08 01:59  댓글주소  수정/삭제  댓글쓰기

    다운받긴 했는데 어떻게 사용하는 건가요? 파이썬같은 건 모르지만 매크로를 사용해보고 싶어서 그러는데...

    • __미니__ 2018.07.09 13:32 신고  댓글주소  수정/삭제

      파이썬 개발 공부용도로 잠깐 만들어본 프로젝트인데 실제로 사용하실줄은 몰랐네요;
      우선 이 프로그램은 윈도우에서 바로 실행 가능한 형식으로 컴파일된 파일이 아닌 파이썬 스크립트이므로 실행을 위해서는 Python 2.7이 필요합니다. 이는 python.org에서 다운받아서 설치가 가능하긴 합니다만 실행도 번거로우실 거고 기능도 많지 않은데다 안정적이지도 않으므로(벌써 2년 방치된 프로젝트...) 다른 매크로를 찾아가시는 게 좋으실 듯 합니다 ㅠㅠ

[C++] CreateMutex

Programming 2016. 11. 22. 16:34



개념만 알고 있던 뮤텍스를 C++ 코드로 직접 작성하여 사용해 봤다.
뮤텍스의 개념은 정말 간단한데, 자원에 한번에 하나의 Thread나 프로세스가 접근하게 하기 위해 사용할 때 잠그고, 나올 때 풀어주며 사용하려 할 때 잠겨있으면 풀릴 때까지 기다리는 것이다.


With_Mutex.cpp

Without_Mutex.cpp


예제 소스는 위에 첨부했다.


- Without_Mutex.cpp

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
#include <iostream>
#include <Windows.h>
 
unsigned int g_num = 0;
 
DWORD WINAPI increase_num(LPVOID max_num)
{
    for (int i = 0; i < (int)max_num; i++) {
        g_num++;
    }
    return 0;
}
 
int main(int argc, char* argv[])
{
    DWORD dThreadId;
    HANDLE hThread_1 = CreateThread(NULL0, increase_num, (LPVOID)1000000&dThreadId);
    HANDLE hThread_2 = CreateThread(NULL0, increase_num, (LPVOID)1000000&dThreadId);
    
    WaitForSingleObject(hThread_1, INFINITE);
    WaitForSingleObject(hThread_2, INFINITE);
 
    std::cout << g_num << std::endl;
    return 0;
}
 
 
cs



뮤텍스 없이 Thread 두 개를 만들어 전역변후 g_num에 1을 더하는 동작을 10만번씩 반복하게 했다.

정상적으로 돌았다면 200000이라는 결과가 나와야 하지만 결과는 다음과 같이 훨씬 작은 값이 나왔다.

동시에 한 자원에 접근했기 때문이다.




- With_Mutex.cpp

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
#include <iostream>
#include <Windows.h>
 
unsigned int g_num = 0;
HANDLE hMutex;
 
DWORD WINAPI increase_num(LPVOID max_num)
{
    for (int i = 0; i < (int)max_num; i++) {
        WaitForSingleObject(hMutex, INFINITE);
        g_num++;
        ReleaseMutex(hMutex);
    }
    return 0;
}
 
int main(int argc, char* argv[])
{
    hMutex = CreateMutex(NULL, FALSE, NULL);
 
    DWORD dThreadId;
    HANDLE hThread_1 = CreateThread(NULL0, increase_num, (LPVOID)1000000&dThreadId);
    HANDLE hThread_2 = CreateThread(NULL0, increase_num, (LPVOID)1000000&dThreadId);
    
    WaitForSingleObject(hThread_1, INFINITE);
    WaitForSingleObject(hThread_2, INFINITE);
 
    std::cout << g_num << std::endl;
    return 0;
}
cs


이번에는 뮤텍스를 가져다가 사용해 봤다.

WaitForSingleObject에 뮤텍스를 넘기면 Release될 때까지 기다린다고 한다.

이후 작업을 수행했으면 Lock이 걸린 Mutex를 Release해준다.



정상적으로 200000이 찍히는 것을 볼 수 있다.




'Programming' 카테고리의 다른 글

[C++] std::for_each  (0) 2016.12.12
[Python] Pacro : Python 기반 매크로 프로그램  (4) 2016.11.28
[C++] CreateMutex  (2) 2016.11.22
[PyQt4] 0x07. WebBrowser  (0) 2016.11.21
[PyQt4] 0x06. QYolk III  (0) 2016.11.18
[PyQt4] 0x05. Final Text Editor  (0) 2016.11.17
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요

  • 익명 2016.11.30 15:29  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • __미니__ 2016.12.01 09:02 신고  댓글주소  수정/삭제

      어제 바로 답변드리려고 했는데 갑자기 좀 바빠져서 답변을 못 드렸었네요.

      무지 오래전에 만든 프로그램이다 보니 거의 흑역사 수준이라 처음부터 다시 짜고 싶은 마음이 굴뚝같지만 일단 간단한 해결법만 알려드리겠습니다.

      myApp 클래스 내부의 함수 sendMessage를 보시면 아마 58번줄에
      sock.send(message)
      라고 되어있을겁니다. 이부분을
      sock.send(message.encode('utf-8'))
      이렇게 바꿔주세요.
      그럼 한글도 입력됩니다~

Qt의 WebView를 이용하여 웹 브라우저를 만들어 보았다.

주소창과 뒤로, 앞으로 버튼, 새로 고침과 중지 버튼이 있으며 따로 브라우저 창의 투명도를 조절할 수 있는 가로 슬라이더도 추가했다.

setWindowOpacity(value) 함수로 윈도우 창의 투명도를 조절할 수 있으며, value의 타입은 0~1 사이의 float이다.



실행 후 네이버에 접속한 모습이다.



네이버에 접속 후 투명도를 낮춘 모습이다.


  [ Source ]


- Main.py


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
# -*- coding: utf-8 -*-
 
# Form implementation generated from reading ui file 'Main.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
 
from PyQt4 import QtCore, QtGui
 
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s
 
try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)
 
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(593395)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.webView = QtWebKit.QWebView(self.centralwidget)
        self.webView.setGeometry(QtCore.QRect(040591331))
        self.webView.setUrl(QtCore.QUrl(_fromUtf8("about:blank")))
        self.webView.setObjectName(_fromUtf8("webView"))
        self.horizontalLayoutWidget = QtGui.QWidget(self.centralwidget)
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(0059141))
        self.horizontalLayoutWidget.setObjectName(_fromUtf8("horizontalLayoutWidget"))
        self.horizontalLayout = QtGui.QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.button_prev = QtGui.QPushButton(self.horizontalLayoutWidget)
        self.button_prev.setObjectName(_fromUtf8("button_prev"))
        self.horizontalLayout.addWidget(self.button_prev)
        self.button_stop = QtGui.QPushButton(self.horizontalLayoutWidget)
        self.button_stop.setObjectName(_fromUtf8("button_stop"))
        self.horizontalLayout.addWidget(self.button_stop)
        self.button_reload = QtGui.QPushButton(self.horizontalLayoutWidget)
        self.button_reload.setObjectName(_fromUtf8("button_reload"))
        self.horizontalLayout.addWidget(self.button_reload)
        self.button_next = QtGui.QPushButton(self.horizontalLayoutWidget)
        self.button_next.setObjectName(_fromUtf8("button_next"))
        self.horizontalLayout.addWidget(self.button_next)
        self.lineEdit_url = QtGui.QLineEdit(self.horizontalLayoutWidget)
        self.lineEdit_url.setObjectName(_fromUtf8("lineEdit_url"))
        self.horizontalLayout.addWidget(self.lineEdit_url)
        self.horizontalSlider_opacity = QtGui.QSlider(self.horizontalLayoutWidget)
        self.horizontalSlider_opacity.setMaximum(99)
        self.horizontalSlider_opacity.setSliderPosition(99)
        self.horizontalSlider_opacity.setOrientation(QtCore.Qt.Horizontal)
        self.horizontalSlider_opacity.setObjectName(_fromUtf8("horizontalSlider_opacity"))
        self.horizontalLayout.addWidget(self.horizontalSlider_opacity)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0059321))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)
 
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow""WebBrowser", None))
        self.button_prev.setText(_translate("MainWindow""<", None))
        self.button_stop.setText(_translate("MainWindow""Stop", None))
        self.button_reload.setText(_translate("MainWindow""Reload", None))
        self.button_next.setText(_translate("MainWindow"">", None))
 
from PyQt4 import QtWebKit
 
cs


- Start.py


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
105
106
107
108
109
110
111
112
113
114
import sys
from Main import Ui_MainWindow
from PyQt4 import QtCore, QtGui, QtWebKit
 
class StartQT4(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.start_page = "about:blank"
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.initialize()
        self.ui.webView.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateAllLinks)
 
        QtCore.QObject.connect(self.ui.lineEdit_url, QtCore.SIGNAL("returnPressed()"), self.url_changed)
        QtCore.QObject.connect(self.ui.button_reload, QtCore.SIGNAL("clicked()"), self.reload_clicked)
        QtCore.QObject.connect(self.ui.button_prev, QtCore.SIGNAL("clicked()"), self.prev_clicked)
        QtCore.QObject.connect(self.ui.button_next, QtCore.SIGNAL("clicked()"), self.next_clicked)
        QtCore.QObject.connect(self.ui.button_stop, QtCore.SIGNAL("clicked()"), self.stop_clicked)
        QtCore.QObject.connect(self.ui.webView, QtCore.SIGNAL("linkClicked (const QUrl&)"), self.link_clicked)
        QtCore.QObject.connect(self.ui.webView, QtCore.SIGNAL("loadProgress (int)"), self.load_progress)
        QtCore.QObject.connect(self.ui.webView, QtCore.SIGNAL("titleChanged (const QString&)"), self.title_changed)
        QtCore.QObject.connect(self.ui.horizontalSlider_opacity, QtCore.SIGNAL("sliderMoved(int)"), self.opacity_changed)
 
    def stop_clicked(self):
        self.ui.webView.stop()
 
    def reload_clicked(self):
        self.ui.webView.setUrl(QtCore.QUrl(self.ui.lineEdit_url.text()))
 
    def prev_clicked(self):
        page = self.ui.webView.page()
        history = page.history()
        history.back()
        if history.canGoBack():
            self.ui.button_prev.setEnabled(True)
        else:
            self.ui.button_prev.setEnabled(False)
 
        self.ui.button_next.setEnabled(True)
 
 
    def next_clicked(self):
        page = self.ui.webView.page()
        history = page.history()
        history.forward()
        if history.canGoForward():
            self.ui.button_next.setEnabled(True)
        else:
            self.ui.button_next.setEnabled(False)
 
        self.ui.button_prev.setEnabled(True)
 
    def url_changed(self):
        # url changed by user
        curr_page = self.ui.webView.page()
        history = curr_page.history()
        if history.canGoBack():
            self.ui.button_prev.setEnabled(True)
        else:
            self.ui.button_prev.setEnabled(False)
 
        if history.canGoForward():
            self.ui.button_next.setEnabled(True)
        else:
            self.ui.button_next.setEnabled(False)
 
        self.ui.button_reload.setEnabled(True)
        url = self.ui.lineEdit_url.text()
        self.ui.webView.setUrl(QtCore.QUrl(url))
 
    def link_clicked(self, url):
        # link clicked
        curr_page = self.ui.webView.page()
        history = curr_page.history()
        if history.canGoBack():
            self.ui.button_prev.setEnabled(True)
        else:
            self.ui.button_prev.setEnabled(False)
 
        if history.canGoForward():
            self.ui.button_next.setEnabled(True)
        else:
            self.ui.button_next.setEnabled(False)
 
        self.ui.button_reload.setEnabled(True)
        self.ui.lineEdit_url.setText(url.toString())
        self.reload_clicked()
 
    def load_progress(self, load):
        if load == 100:
            self.ui.button_stop.setEnabled(False)
        else:
            self.ui.button_stop.setEnabled(True)
 
    def title_changed(self, title):
        self.setWindowTitle(title)
 
    def opacity_changed(self, value):
        self.setWindowOpacity((value + 1)/100.0)
 
 
    def initialize(self):
        self.ui.button_prev.setEnabled(False)
        self.ui.button_next.setEnabled(False)
        self.ui.button_stop.setEnabled(False)
        self.ui.button_reload.setEnabled(False)
        self.ui.lineEdit_url.setText(self.start_page)
        self.ui.webView.setUrl(QtCore.QUrl(self.start_page))
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = StartQT4()
    myapp.show()
    sys.exit(app.exec_())
cs


github : https://github.com/skyclad0x7b7/StudyPyQt4/tree/master/0x07.%20WebBrowser





'Programming' 카테고리의 다른 글

[Python] Pacro : Python 기반 매크로 프로그램  (4) 2016.11.28
[C++] CreateMutex  (2) 2016.11.22
[PyQt4] 0x07. WebBrowser  (0) 2016.11.21
[PyQt4] 0x06. QYolk III  (0) 2016.11.18
[PyQt4] 0x05. Final Text Editor  (0) 2016.11.17
[PyQt4] 0x04. QYolk II  (0) 2016.11.16
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요

[PyQt4] 0x06. QYolk III

Programming 2016. 11. 18. 15:48


http://5kyc1ad.tistory.com/246 에서 만든 QYolk II에 기능을 조금 추가했다.

업데이트 탭을 추가하고 최신 버전이 아닌 패키지가 있을 경우 표시하고 몇 버전으로 업그레이드가 가능한지를 나타내었다.


  [ Source ]


- Main.py


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
# -*- coding: utf-8 -*-
 
# Form implementation generated from reading ui file 'Main.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
 
from PyQt4 import QtCore, QtGui
 
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s
 
try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)
 
class Ui_QYolk(object):
    def setupUi(self, QYolk):
        QYolk.setObjectName(_fromUtf8("QYolk"))
        QYolk.resize(565345)
        self.centralwidget = QtGui.QWidget(QYolk)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.tab_widget = QtGui.QTabWidget(self.centralwidget)
        self.tab_widget.setGeometry(QtCore.QRect(100551291))
        self.tab_widget.setObjectName(_fromUtf8("tab_widget"))
        self.tab_all_packages = QtGui.QWidget()
        self.tab_all_packages.setObjectName(_fromUtf8("tab_all_packages"))
        self.all_list = QtGui.QTreeWidget(self.tab_all_packages)
        self.all_list.setGeometry(QtCore.QRect(00541261))
        self.all_list.setObjectName(_fromUtf8("all_list"))
        self.tab_widget.addTab(self.tab_all_packages, _fromUtf8(""))
        self.tab_active = QtGui.QWidget()
        self.tab_active.setObjectName(_fromUtf8("tab_active"))
        self.active_list = QtGui.QTreeWidget(self.tab_active)
        self.active_list.setGeometry(QtCore.QRect(00541261))
        self.active_list.setObjectName(_fromUtf8("active_list"))
        self.tab_widget.addTab(self.tab_active, _fromUtf8(""))
        self.tab_not_active = QtGui.QWidget()
        self.tab_not_active.setObjectName(_fromUtf8("tab_not_active"))
        self.not_active_list = QtGui.QTreeWidget(self.tab_not_active)
        self.not_active_list.setGeometry(QtCore.QRect(00541261))
        self.not_active_list.setObjectName(_fromUtf8("not_active_list"))
        self.tab_widget.addTab(self.tab_not_active, _fromUtf8(""))
        self.tab_update = QtGui.QWidget()
        self.tab_update.setObjectName(_fromUtf8("tab_update"))
        self.update_list = QtGui.QTreeWidget(self.tab_update)
        self.update_list.setGeometry(QtCore.QRect(00551271))
        self.update_list.setObjectName(_fromUtf8("update_list"))
        self.tab_widget.addTab(self.tab_update, _fromUtf8(""))
        self.info_label = QtGui.QLabel(self.centralwidget)
        self.info_label.setGeometry(QtCore.QRect(1028554131))
        self.info_label.setObjectName(_fromUtf8("info_label"))
        QYolk.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(QYolk)
        self.menubar.setGeometry(QtCore.QRect(0056521))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        QYolk.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(QYolk)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        QYolk.setStatusBar(self.statusbar)
 
        self.retranslateUi(QYolk)
        self.tab_widget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(QYolk)
 
    def retranslateUi(self, QYolk):
        QYolk.setWindowTitle(_translate("QYolk""QYolk III", None))
        self.all_list.headerItem().setText(0, _translate("QYolk""Package Name", None))
        self.all_list.headerItem().setText(1, _translate("QYolk""Version", None))
        self.all_list.headerItem().setText(2, _translate("QYolk""Status", None))
        self.tab_widget.setTabText(self.tab_widget.indexOf(self.tab_all_packages), _translate("QYolk""All Packages", None))
        self.active_list.headerItem().setText(0, _translate("QYolk""Package Name", None))
        self.active_list.headerItem().setText(1, _translate("QYolk""Version", None))
        self.active_list.headerItem().setText(2, _translate("QYolk""Status", None))
        self.tab_widget.setTabText(self.tab_widget.indexOf(self.tab_active), _translate("QYolk""Active", None))
        self.not_active_list.headerItem().setText(0, _translate("QYolk""Package Name", None))
        self.not_active_list.headerItem().setText(1, _translate("QYolk""Version", None))
        self.not_active_list.headerItem().setText(2, _translate("QYolk""Status", None))
        self.tab_widget.setTabText(self.tab_widget.indexOf(self.tab_not_active), _translate("QYolk""Not Active", None))
        self.update_list.headerItem().setText(0, _translate("QYolk""Package Name", None))
        self.update_list.headerItem().setText(1, _translate("QYolk""Installed Version", None))
        self.update_list.headerItem().setText(2, _translate("QYolk""Available Version", None))
        self.tab_widget.setTabText(self.tab_widget.indexOf(self.tab_update), _translate("QYolk""Updates", None))
        self.info_label.setText(_translate("QYolk""TextLabel", None))
 
 
cs


- Start.py


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
import sys
from Main import Ui_QYolk
from PyQt4 import QtCore, QtGui
from yolk import yolklib
from os.path import expanduser
from yolk.cli import get_pkglist
from yolk.yolklib import get_highest_version, get_distributions, get_highest_installed
from yolk.pypi import CheeseShop
import pkg_resources
from os.path import isfile
from datetime import timedelta
from datetime import datetime
 
class StartQT4(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_QYolk()
        self.ui.setupUi(self)
        self.ui.info_label.setText("")
 
        # set Column Width
        self.ui.all_list.setColumnWidth(0200)
        self.ui.all_list.setColumnWidth(1200)
        self.ui.active_list.setColumnWidth(0200)
        self.ui.active_list.setColumnWidth(1200)
        self.ui.not_active_list.setColumnWidth(0200)
        self.ui.not_active_list.setColumnWidth(1200)
        self.ui.update_list.setColumnWidth(0200)
        self.ui.update_list.setColumnWidth(1200)
 
        QtCore.QObject.connect(self.ui.tab_widget, QtCore.SIGNAL("currentChanged(int)"), self.tab_changed)
 
        packages = get_distributions('all')
        for pkg in packages:
            newItem = QtGui.QTreeWidgetItem(self.ui.all_list)
            pk = str(pkg[0]).split(' ')
            if pkg[1]:
                status = 'Active'
            else:
                status = 'Not Active'
                newItem.setTextColor(0, QtGui.QColor(128128128))
                newItem.setTextColor(1, QtGui.QColor(128128128))
                newItem.setTextColor(2, QtGui.QColor(128128128))
                
            newItem.setText(0, pk[0])
            newItem.setText(1, pk[1])
            newItem.setText(2, status)
 
        for pkg in get_distributions('active'):
            newItem = QtGui.QTreeWidgetItem(self.ui.active_list)
            pk = str(pkg[0]).split(' ')
            newItem.setText(0, pk[0])
            newItem.setText(1, pk[1])
            newItem.setText(2'Active')
 
        for pkg in get_distributions('nonactive'):
            newItem = QtGui.QTreeWidgetItem(self.ui.not_active_list)
            pk = str(pkg[0]).split(' ')
            newItem.setText(0, pk[0])
            newItem.setText(1, pk[1])
            newItem.setText(2'Not Active')
 
    def tab_changed(self, column):
        if column == 0:
            message = "<b>QYolk</b> : Browsing all installed cheeseshop packages"
        elif column == 1:
            message = "<b>QYolk</b> : Browsing active packages"
        elif column == 2:
            message = "<b>QYolk</b> : Browsing not active packages (older versions)"
        elif column == 3:
            message = "<b>QYolk</b> : Browsing available updates"
            for pkg in get_fresh_updates():
                newItem = QtGui.QTreeWidgetItem(self.ui.update_list)
                newItem.setText(0, pkg[0])
                newItem.setText(1, pkg[1])
                newItem.setText(2, pkg[2])
 
        self.ui.info_label.setText(message)
 
        
 
def get_fresh_updates(package_name = "", version = ""):
    ret = []
    pypi = CheeseShop()
    for pkg in get_pkglist():
        for (dist, active) in get_distributions("all", pkg, get_highest_installed(pkg)):
            (project_name, versions) = pypi.query_versions_pypi(dist.project_name)
            if versions:
                newest = get_highest_version(versions)
                if newest != dist.version:
                    if pkg_resources.parse_version(dist.version) < pkg_resources.parse_version(newest):
                        ret.append([project_name, dist.version, newest])
 
    return ret
 
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = StartQT4()
    myapp.show()
    sys.exit(app.exec_())
cs


github : https://github.com/skyclad0x7b7/StudyPyQt4/tree/master/0x06.%20QYolk%20III

'Programming' 카테고리의 다른 글

[C++] CreateMutex  (2) 2016.11.22
[PyQt4] 0x07. WebBrowser  (0) 2016.11.21
[PyQt4] 0x06. QYolk III  (0) 2016.11.18
[PyQt4] 0x05. Final Text Editor  (0) 2016.11.17
[PyQt4] 0x04. QYolk II  (0) 2016.11.16
[PyQt4] 0x03. QYolk I  (6) 2016.11.15
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요

0x02. Extended Text Editor에서 만들었던 텍스트 에디터에 기능을 더 추가하여 만들었다.

수정 중인 파일을 다른 프로세스에서 수정하거나 삭제했을 경우, 그것을 감지하여 다시 로드할지, 덮어쓸지를 정할 수 있다.

File Save할 때도 파일 다이얼로그를 열어 저장할 위치를 선택 가능하게 하였다.


UI는 Window Title을 'Final Text Editor'로 바꾼 것 외에는 변한 게 없고 Start.py의 내부 코드만 좀 추가되었다.




  [ Source ]


- Main.py


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
# -*- coding: utf-8 -*-
 
# Form implementation generated from reading ui file 'Main.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
 
from PyQt4 import QtCore, QtGui
 
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s
 
try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)
 
class Ui_notepad(object):
    def setupUi(self, notepad):
        notepad.setObjectName(_fromUtf8("notepad"))
        notepad.resize(802625)
        self.centralwidget = QtGui.QWidget(notepad)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.textBrowser = QtGui.QTextBrowser(self.centralwidget)
        self.textBrowser.setGeometry(QtCore.QRect(1040781541))
        self.textBrowser.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByKeyboard|QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextBrowserInteraction|QtCore.Qt.TextEditable|QtCore.Qt.TextEditorInteraction|QtCore.Qt.TextSelectableByKeyboard|QtCore.Qt.TextSelectableByMouse)
        self.textBrowser.setObjectName(_fromUtf8("textBrowser"))
        self.button_open = QtGui.QPushButton(self.centralwidget)
        self.button_open.setGeometry(QtCore.QRect(10107523))
        self.button_open.setObjectName(_fromUtf8("button_open"))
        self.button_save = QtGui.QPushButton(self.centralwidget)
        self.button_save.setGeometry(QtCore.QRect(90107523))
        self.button_save.setCheckable(False)
        self.button_save.setAutoDefault(False)
        self.button_save.setDefault(False)
        self.button_save.setFlat(False)
        self.button_save.setObjectName(_fromUtf8("button_save"))
        self.button_close = QtGui.QPushButton(self.centralwidget)
        self.button_close.setGeometry(QtCore.QRect(710107523))
        self.button_close.setObjectName(_fromUtf8("button_close"))
        notepad.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(notepad)
        self.menubar.setGeometry(QtCore.QRect(0080221))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        notepad.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(notepad)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        notepad.setStatusBar(self.statusbar)
 
        self.retranslateUi(notepad)
        QtCore.QMetaObject.connectSlotsByName(notepad)
 
    def retranslateUi(self, notepad):
        notepad.setWindowTitle(_translate("notepad""Final Text Editor", None))
        self.button_open.setText(_translate("notepad""Open", None))
        self.button_save.setText(_translate("notepad""Save", None))
        self.button_close.setText(_translate("notepad""Close", None))
 
 
cs


- Start.py


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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import sys
import codecs
from os.path import isfile
from PyQt4 import QtCore, QtGui
from Main import Ui_notepad
 
class StartQT4(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_notepad()
        self.ui.setupUi(self)
        self.watcher = QtCore.QFileSystemWatcher(self)
 
        QtCore.QObject.connect(self.ui.button_open, QtCore.SIGNAL("clicked()"), self.file_dialog)
        QtCore.QObject.connect(self.ui.button_save, QtCore.SIGNAL("clicked()"), self.file_save)
        QtCore.QObject.connect(self.ui.textBrowser, QtCore.SIGNAL("textChanged()"), self.enable_save)
        QtCore.QObject.connect(self.ui.button_close, QtCore.SIGNAL("clicked()"), self.file_close)
        QtCore.QObject.connect(self.watcher, QtCore.SIGNAL("fileChanged(const QString&)"), self.file_changed)
        self.initalize()
 
    def initalize(self):
        self.ui.textBrowser.setPlainText("")
        self.ui.button_save.setEnabled(False)
        self.setWindowTitle("Final Text Editor")
        self.filename = ""
 
    def file_dialog(self):
        fd = QtGui.QFileDialog(self)
        newFile = fd.getOpenFileName()
        if isfile(newFile) and self.filename != newFile:
            s = codecs.open(newFile, 'r''utf-8').read()
            self.ui.textBrowser.setPlainText(s)
            self.setWindowTitle(newFile)
            self.ui.button_save.setEnabled(False)
            if self.filename != "":
                self.watcher.removePath(self.filename)
            self.watcher.addPath(newFile)
            self.filename = newFile
 
    def enable_save(self):
        self.ui.button_save.setEnabled(True)
 
    def file_save(self):
        if self.filename != "" and isfile(self.filename): # File Opened and exists
            file = codecs.open(self.filename, 'w''utf-8')
            file.write(unicode(self.ui.textBrowser.toPlainText()))
            file.close()
            self.ui.button_save.setEnabled(False)
        else# File not opened or not exists
            fd = QtGui.QFileDialog(self)
            newFile = fd.getSaveFileName()
            if newFile:
                s = codecs.open(newFile, 'w''utf-8')
                s.write(unicode(self.ui.textBrowser.toPlainText()))
                s.close();
                self.ui.button_save.setEnabled(False)
 
 
    def file_close(self):
        if isfile(self.filename):
            # not saved
            if self.ui.button_save.isEnabled():
                message = QtGui.QMessageBox(self)
                message.setText('Would you like to save the file before closing?')
                message.setWindowTitle("Warning")
                message.setIcon(QtGui.QMessageBox.Question)
                message.addButton('Save', QtGui.QMessageBox.AcceptRole)
                message.addButton('Discard', QtGui.QMessageBox.DestructiveRole)
                message.addButton('Cancel', QtGui.QMessageBox.RejectRole)
                message.setDetailedText('Unsaved changes in file: ' + str(self.filename))
                message.exec_()
                response = message.clickedButton().text()
                if response == 'Save':
                    self.file_save()
                    self.ui.button_save.setEnabled(False)
                elif response == 'Discard':
                    self.initalize()
                else:
                    pass
            else:
                self.initalize()
 
    def file_changed(self, path):
        response = False
 
        # Button texts
        SAVE     = 'Save AS'
        RELOAD     = 'Reload File'
        CANCEL     = 'Cancel'
        message = QtGui.QMessageBox(self)
        message.setText('Opened file have been changed!')
        message.setWindowTitle('Final Text Editor')
        message.setIcon(QtGui.QMessageBox.Warning)
        message.addButton(SAVE, QtGui.QMessageBox.AcceptRole)
        message.addButton(RELOAD, QtGui.QMessageBox.DestructiveRole)
        message.addButton(CANCEL, QtGui.QMessageBox.RejectRole)
        message.setDetailedText('The File "{0}" have been changed or removed by other application. What do you want to do?'.format(self.filename))
        message.exec_()
        response = message.clickedButton().text()
        # Save Current File to new
        if response == SAVE:
            fd = QtGui.QFileDialog(self)
            newFile = fd.getSaveFileName()
            if newFile:
                s = codecs.open(newFile, 'w''utf-8')
                s.write(unicode(self.ui.textBrowser.toPlainText()))
                s.close()
                self.ui.button_save.setEnabled(False)
                # new file, remove old and add the new one to the watcher
                if self.filename and str(newFile) != str(self.filename):
                    self.watcher.removePath(self.filename)
                    self.watcher.addPath(newFile)
                    self.filename = newFile
        # reload the text in the editor
        elif response == RELOAD:
            s = codecs.open(self.filename, 'r''utf-8').read()
            self.ui.textBrowser.setPlainText(s)
            self.ui.button_save.setEnabled(False)
 
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = StartQT4()
    myapp.show()
    sys.exit(app.exec_())
cs


github : https://github.com/skyclad0x7b7/StudyPyQt4/tree/master/0x05.%20Final%20Text%20Editor

'Programming' 카테고리의 다른 글

[PyQt4] 0x07. WebBrowser  (0) 2016.11.21
[PyQt4] 0x06. QYolk III  (0) 2016.11.18
[PyQt4] 0x05. Final Text Editor  (0) 2016.11.17
[PyQt4] 0x04. QYolk II  (0) 2016.11.16
[PyQt4] 0x03. QYolk I  (6) 2016.11.15
[PyQt4] 0x02. Extended Text Editor  (0) 2016.11.15
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요

[PyQt4] 0x04. QYolk II

Programming 2016. 11. 16. 10:17

이전에 짰던 QYolk에 탭을 추가하여 Active상태인 것과 Not Active 상태인 것을 나눠서 볼 수 있게 하였다.

밑에 Label도 추가하여 탭을 변경 시 해당 탭에 대한 설명이 간략하게 나타나도록 설정하였다.



++ 2016.11.18

- Yolk 라이브러리를 https://pypi.python.org/pypi/yolk3k 로 업데이트하면서 함수를 일부 변경하였습니다. 

- ui에서 Version을 Package name이라고 잘못 작성하여 수정하였습니다.






 [ Source ]


- Main.py


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
# -*- coding: utf-8 -*-
 
# Form implementation generated from reading ui file 'Main.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
 
from PyQt4 import QtCore, QtGui
 
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s
 
try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)
 
class Ui_QYolk(object):
    def setupUi(self, QYolk):
        QYolk.setObjectName(_fromUtf8("QYolk"))
        QYolk.resize(565345)
        self.centralwidget = QtGui.QWidget(QYolk)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.tab_widget = QtGui.QTabWidget(self.centralwidget)
        self.tab_widget.setGeometry(QtCore.QRect(100551291))
        self.tab_widget.setObjectName(_fromUtf8("tab_widget"))
        self.tab_all_packages = QtGui.QWidget()
        self.tab_all_packages.setObjectName(_fromUtf8("tab_all_packages"))
        self.all_list = QtGui.QTreeWidget(self.tab_all_packages)
        self.all_list.setGeometry(QtCore.QRect(00541261))
        self.all_list.setObjectName(_fromUtf8("all_list"))
        self.tab_widget.addTab(self.tab_all_packages, _fromUtf8(""))
        self.tab_active = QtGui.QWidget()
        self.tab_active.setObjectName(_fromUtf8("tab_active"))
        self.active_list = QtGui.QTreeWidget(self.tab_active)
        self.active_list.setGeometry(QtCore.QRect(00541261))
        self.active_list.setObjectName(_fromUtf8("active_list"))
        self.tab_widget.addTab(self.tab_active, _fromUtf8(""))
        self.tab_not_active = QtGui.QWidget()
        self.tab_not_active.setObjectName(_fromUtf8("tab_not_active"))
        self.not_active_list = QtGui.QTreeWidget(self.tab_not_active)
        self.not_active_list.setGeometry(QtCore.QRect(00541261))
        self.not_active_list.setObjectName(_fromUtf8("not_active_list"))
        self.tab_widget.addTab(self.tab_not_active, _fromUtf8(""))
        self.info_label = QtGui.QLabel(self.centralwidget)
        self.info_label.setGeometry(QtCore.QRect(1028554131))
        self.info_label.setObjectName(_fromUtf8("info_label"))
        QYolk.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(QYolk)
        self.menubar.setGeometry(QtCore.QRect(0056521))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        QYolk.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(QYolk)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        QYolk.setStatusBar(self.statusbar)
 
        self.retranslateUi(QYolk)
        self.tab_widget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(QYolk)
 
    def retranslateUi(self, QYolk):
        QYolk.setWindowTitle(_translate("QYolk""QYolk II", None))
        self.all_list.headerItem().setText(0, _translate("QYolk""Package Name", None))
        self.all_list.headerItem().setText(1, _translate("QYolk""Version", None))
        self.all_list.headerItem().setText(2, _translate("QYolk""Status", None))
        self.tab_widget.setTabText(self.tab_widget.indexOf(self.tab_all_packages), _translate("QYolk""All Packages", None))
        self.active_list.headerItem().setText(0, _translate("QYolk""Package Name", None))
        self.active_list.headerItem().setText(1, _translate("QYolk""Version", None))
        self.active_list.headerItem().setText(2, _translate("QYolk""Status", None))
        self.tab_widget.setTabText(self.tab_widget.indexOf(self.tab_active), _translate("QYolk""Active", None))
        self.not_active_list.headerItem().setText(0, _translate("QYolk""Package Name", None))
        self.not_active_list.headerItem().setText(1, _translate("QYolk""Version", None))
        self.not_active_list.headerItem().setText(2, _translate("QYolk""Status", None))
        self.tab_widget.setTabText(self.tab_widget.indexOf(self.tab_not_active), _translate("QYolk""Not Active", None))
        self.info_label.setText(_translate("QYolk""TextLabel", None))
 
 
cs


- Start.py


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
import sys
from PyQt4 import QtCore, QtGui
from Main import Ui_QYolk
from yolk import yolklib
 
class StartQT4(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_QYolk()
        self.ui.setupUi(self)
        self.ui.info_label.setText("")
 
        # set Column Width
        self.ui.all_list.setColumnWidth(0200)
        self.ui.all_list.setColumnWidth(1200)
        self.ui.active_list.setColumnWidth(0200)
        self.ui.active_list.setColumnWidth(1200)
        self.ui.not_active_list.setColumnWidth(0200)
        self.ui.not_active_list.setColumnWidth(1200)
 
        QtCore.QObject.connect(self.ui.tab_widget, QtCore.SIGNAL("currentChanged(int)"), self.tab_changed)
 
        packages = yolklib.get_distributions('all')
        for pkg in packages:
            newItem = QtGui.QTreeWidgetItem(self.ui.all_list)
            pk = str(pkg[0]).split(' ')
            if pkg[1]:
                status = 'Active'
            else:
                status = 'Not Active'
                newItem.setTextColor(0, QtGui.QColor(128128128))
                newItem.setTextColor(1, QtGui.QColor(128128128))
                newItem.setTextColor(2, QtGui.QColor(128128128))
                
            newItem.setText(0, pk[0])
            newItem.setText(1, pk[1])
            newItem.setText(2, status)
 
        for pkg in yolklib.get_distributions('active'):
            newItem = QtGui.QTreeWidgetItem(self.ui.active_list)
            pk = str(pkg[0]).split(' ')
            newItem.setText(0, pk[0])
            newItem.setText(1, pk[1])
            newItem.setText(2'Active')
 
        for pkg in yolklib.get_distributions('nonactive'):
            newItem = QtGui.QTreeWidgetItem(self.ui.not_active_list)
            pk = str(pkg[0]).split(' ')
            newItem.setText(0, pk[0])
            newItem.setText(1, pk[1])
            newItem.setText(2'Not Active')
 
    def tab_changed(self, column):
        if column == 0:
            message = "<b>QYolk</b> : Browsing all installed cheeseshop packages"
        elif column == 1:
            message = "<b>QYolk</b> : Browsing active packages"
        elif column == 2:
            message = "<b>QYolk</b> : Browsing not active packages (older versions)"
 
        self.ui.info_label.setText(message)
 
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = StartQT4()
    myapp.show()
    sys.exit(app.exec_())
cs


github : https://github.com/skyclad0x7b7/StudyPyQt4/tree/master/0x04.%20QYolk%20II

'Programming' 카테고리의 다른 글

[PyQt4] 0x06. QYolk III  (0) 2016.11.18
[PyQt4] 0x05. Final Text Editor  (0) 2016.11.17
[PyQt4] 0x04. QYolk II  (0) 2016.11.16
[PyQt4] 0x03. QYolk I  (6) 2016.11.15
[PyQt4] 0x02. Extended Text Editor  (0) 2016.11.15
[PyQt4] 0x01. PyQt4 설치, Simple text editor  (0) 2016.11.15
블로그 이미지

__미니__

E-mail : skyclad0x7b7@gmail.com 나와 계약해서 슈퍼 하-카가 되어 주지 않을래?

댓글을 달아 주세요