728x90
반응형

 

2021.06.04 - [FRONT-END/React] - [React] 리액트 & socket.io 기반 채팅 어플리케이션 만들기 - 2

 

[React] 리액트 & socket.io 기반 채팅 어플리케이션 만들기 - 2

1탄을 보지 않고 2탄부터 오셨다면 꼭 보고 오시길 바랍니다. 2021.06.04 - [FRONT-END/React] - [React] React로 Chat Application 구현하기 -1 [React] React로 Chat Application 구현하기 -1 https://www.youtu..

hello-ming.tistory.com

 

이어서 할것이다!

 

이번 포스팅에는 전 포스팅에서 폴더와 js파일을 만들어놨었는데 이번에는 js 내용을 채울것이다!

 

server에 users.js를 생성한 후 내용을 채운다.

 

const users = []

const addUser = ({ id, name, room }) => {
//이름의 공백 제거
  name = name.trim().toLowerCase()
  room = room.trim().toLowerCase()

  const existingUser = users.find(
    (user) => user.room === room && user.name === name
  )

  if (!name || !room) return { error: '사용자 이름과 방이 필요합니다.' }
  if (existingUser) return { error: '이미 사용중인 이름입니다.' }

  const user = { id, name, room }

  users.push(user)

  return { user }
}

const removeUser = (id) => {
  const index = users.findIndex((user) => user.id === id)

  if (index !== -1) return users.splice(index, 1)[0]
}

const getUser = (id) => users.find((user) => user.id === id)

const getUsersInRoom = (room) => users.filter((user) => user.room === room)

module.exports = { addUser, removeUser, getUser, getUsersInRoom }

 

기존에 만들어 놓은 server/index.js에 아래의 내용으로 바꿔준다.

const express = require('express')
const socketio = require('socket.io')
const http = require('http')

const cors = require('cors')
const router = require('./router')
const { addUser, removeUser, getUser, getUsersInRoom } = require('./users.js')

const PORT = process.env.PORT || 5000

const app = express()
const server = http.createServer(app)
const io = socketio(server)
app.use(cors())
app.use(router)

io.on('connection', (socket) => {
  console.log('새로운 connection이 발생하였습니다.')
  socket.on('join', ({ name, room }, callback) => {
    const { error, user } = addUser({ id: socket.id, name, room })
    if (error) callback({ error: '에러가 발생했어요.' })

    socket.emit('message', {
      user: 'admin',
      text: `${user.name}, ${user.room}에 오신것을 환영합니다.`,
    })
    socket.broadcast.to(user.room).emit('message', {
      user: 'admin',
      text: `${user.name} 님이 가입하셨습니다.`,
    })
    io.to(user.room).emit('roomData', {
      room: user.room,
      users: getUsersInRoom(user.room),
    })
    socket.join(user.room)

    callback()
  })
  socket.on('sendMessage', (message, callback) => {
    const user = getUser(socket.id)
    io.to(user.room).emit('message', { user: user.name, text: message })
    callback()
  })
  socket.on('disconnect', () => {
    const user = removeUser(socket.id)

    if (user) {
      io.to(user.room).emit('message', {
        user: 'Admin',
        text: `${user.name} 님이 방을 나갔습니다.`,
      })
      io.to(user.room).emit('roomData', {
        room: user.room,
        users: getUsersInRoom(user.room),
      })
    }
    console.log('유저가 떠났어요.')
  })
})
server.listen(PORT, () => console.log(`서버가 ${PORT} 에서 시작되었어요`))

 

Chat.js을 수정한다.

import React, { useState, useEffect } from 'react'
import queryString from 'query-string'
import io from 'socket.io-client'

import TextContainer from '../TextContainer/TextContainer'
import Messages from '../Messages/Messages'
import InfoBar from '../InfoBar/InfoBar'
import Input from '../Input/Input'

import './Chat.css'

const ENDPOINT = 'http://localhost:5000'

let socket

const Chat = ({ location }) => {
  const [name, setName] = useState('')
  const [room, setRoom] = useState('')
  const [users, setUsers] = useState('')
  const [message, setMessage] = useState('')
  const [messages, setMessages] = useState([])

  useEffect(() => {
    const { name, room } = queryString.parse(location.search)

    socket = io(ENDPOINT)

    setRoom(room)
    setName(name)

    socket.emit('join', { name, room }, (error) => {
      if (error) {
        alert(error)
      }
    })
  }, [ENDPOINT, location.search])

  useEffect(() => {
    socket.on('message', (message) => {
      setMessages((messages) => [...messages, message])
    })

    socket.on('roomData', ({ users }) => {
      setUsers(users)
    })
  }, [])

  const sendMessage = (event) => {
    event.preventDefault()

    if (message) {
      socket.emit('sendMessage', message, () => setMessage(''))
    }
  }

  return (
    <div className='outerContainer'>
      <div className='container'>
        <InfoBar room={room} />
        <Messages messages={messages} name={name} />
        <Input
          message={message}
          setMessage={setMessage}
          sendMessage={sendMessage}
        />
      </div>
      <TextContainer users={users} />
    </div>
  )
}

export default Chat

 

infoBar.js에 내용을 추가한다.

import React from 'react'

import onlineIcon from '../../icons/onlineIcon.png'
import closeIcon from '../../icons/closeIcon.png'

import './InfoBar.css'

const InfoBar = () => {
  ;<div className='infoBar'>
    <div className='leftInnerContainer'>
      <img className='onlineIcon' src={onlineIcon} alt='online icon' />
      <h3>{room}</h3>
    </div>
    <div className='rightInnerContainer'>
      <a href='/'>
        <img src={closeIcon} alt='close icon' />
      </a>
    </div>
  </div>
}

export default InfoBar

 

위 코드의 png를 적용하기 위해 사진을 넣어줄 것이다.

 

코드안의 경로와 맞게 src에 icons라는 폴더를 만들어 이미지를 넣어주면 된다. 

 

이미지.zip
0.00MB

 

input.js에 내용을 추가한다.

import React from 'react'

import './Input.css'

const Input = ({ setMessage, sendMessage, message }) => (
  <form className='form'>
    <input
      className='input'
      type='text'
      placeholder='전송하려는 메세지를 입력하세요.'
      value={message}
      onChange={({ target: { value } }) => setMessage(value)}
      onKeyPress={(event) =>
        event.key === 'Enter' ? sendMessage(event) : null
      }
    />
    <button className='sendButton' onClick={(e) => sendMessage(e)}>
      전송
    </button>
  </form>
)

export default Input

 

Messages폴더 안의 Messages.js에 내용을 추가한다.

import React from 'react'

import ScrollToBottom from 'react-scroll-to-bottom'

import Message from './Message/Message'

import './Messages.css'

const Messages = ({ messages, name }) => (
  <ScrollToBottom className='messages'>
    {messages.map((message, i) => (
      <div key={i}>
        <Message message={message} name={name} />
      </div>
    ))}
  </ScrollToBottom>
)

export default Messages

 

Messages폴더 안의 Message의 Message.js에 내용을 추가한다.

import React from 'react'

import './Message.css'

import ReactEmoji from 'react-emoji'

const Message = ({ message: { text, user }, name }) => {
  let isSentByCurrentUser = false

  const trimmedName = name.trim().toLowerCase()

  if (user === trimmedName) {
    isSentByCurrentUser = true
  }

  return isSentByCurrentUser ? (
    <div className='messageContainer justifyEnd'>
      <p className='sentText pr-10'>{trimmedName}</p>
      <div className='messageBox backgroundBlue'>
        <p className='messageText colorWhite'>{ReactEmoji.emojify(text)}</p>
      </div>
    </div>
  ) : (
    <div className='messageContainer justifyStart'>
      <div className='messageBox backgroundLight'>
        <p className='messageText colorDark'>{ReactEmoji.emojify(text)}</p>
      </div>
      <p className='sentText pl-10 '>{user}</p>
    </div>
  )
}

export default Message

 

TextContainer.js에도 내용을 추가한다.

import React from 'react'

import onlineIcon from '../../icons/onlineIcon.png'

import './TextContainer.css'

const TextContainer = ({ users }) => (
  <div className='textContainer'>
    <div>
      <h1>
        실시간 채팅 프로그램{' '}
        <span role='img' aria-label='emoji'>
          💬
        </span>
      </h1>
      <h2>
        Created with React, Express, Node and Socket.IO{' '}
        <span role='img' aria-label='emoji'>
          ❤️
        </span>
      </h2>
      <h2>
        Try it out right now!{' '}
        <span role='img' aria-label='emoji'>
          ⬅️
        </span>
      </h2>
    </div>
    {users ? (
      <div>
        <h1>현재 채팅중인 사람들 : </h1>
        <div className='activeContainer'>
          <h2>
            {users.map(({ name }) => (
              <div key={name} className='activeItem'>
                {name}
                <img alt='Online Icon' src={onlineIcon} />
              </div>
            ))}
          </h2>
        </div>
      </div>
    ) : null}
  </div>
)

export default TextContainer

 

모든 코드를 작성하면 

 

localhost:3000/ 에 이런 화면이 뜨고 가입을 누르면

 

 

채팅창이 뜬것을 확인할 수 있다.

 

다음 포스팅은 전체적인 채팅방 동작과 코드설명을 할 것이다.

728x90
반응형
728x90
반응형

 

본 포스팅을 시작하기 앞서 나는 MongoDB Compass가 깔려있는 상태이다.

 

 

backend폴더로 이동해 (즉 server의 위치) 

 

mongoose.connect(process.env.MONGODB_URL || 'mongodb://localhost/amazona', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  useCreateIndex: true,
})

이걸 붙여준다 나는 express() 밑에  붙여주었다.

 

mongoose를 설치했는데도 import가 되지 않을때는 

 

npm i express-async-handler

 

 

테스트 하기위에 data.js에 users 데이터를 추가해준다.

 

data.js

import bcrypt from 'bcryptjs'

const data = {
  users: [
    {
      name: 'Basir',
      email: 'adming@example.com',
      password: bcrypt.hashSync('1234', 8),
      isAdmin: false,
    },
    {
      name: 'John',
      email: 'John@example.com',
      password: bcrypt.hashSync('1234', 8),
      isAdmin: false,
    },
  ]}

 

MongoDB Cluster에 접속하여 구글계정으로 로그인 하고 

본명이 있어 급하게 지웠다.

 

나의 MongoDB 주소를 알 수 있다. 이것을

 

아까 mongoose.connect() 코드에 url 주소를 붙여준다.

 

mongoose.connect(
  process.env.MONGODB_URL ||
    'mongodb+srv://(아이디):(비밀번호)@cluster0.bueqv.mongodb.net/test',
  {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true,
  }
)

 

테스트 하기위해 인터넷 창에

 

http://localhost:5000/api/users/seed

 검색한다.

 

아까 data.js에 users 데이터를 추가한 것이 JSON형식으로 보인다.(저는 JSON Viewer를 설치했기 때문에 보여요.)

 

 

MongoDB Compass 클릭하면 tests에 user 데이터가 들어왔음을 확인할 수 있다.

 

728x90
반응형
728x90
반응형

 

1탄을 보지 않고 2탄부터 오셨다면 꼭 보고 오시길 바랍니다.

 

2021.06.04 - [FRONT-END/React] - [React] React로 Chat Application 구현하기 -1

 

[React] React로 Chat Application 구현하기 -1

https://www.youtube.com/watch?v=ZwFA3YMfkoc https://github.com/adrianhajdin/project_chat_application adrianhajdin/project_chat_application This is a code repository for the corresponding YouTube vid..

hello-ming.tistory.com


 

1탄에서는 서버와 연결됨을 확인하였다. 정리를 하면

 

 

1탄에 이어서 하려고 한다!

 

 

Join.js의 내용을 바꿔준다.

import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import './Join.css'

const Join = () => {
  const [name, setName] = useState('')
  const [room, setRoom] = useState('')
  return (
    <div className='joinOuterContainer'>
      <div className='joinInnerContainer'>
        <h1 className='heading'></h1>
        <div>
          <input
            placeholder='이름'
            className='joinInput'
            type='text'
            onChange={(event) => setName(event.target.value)}
          />
        </div>
        <div>
          <input
            placeholder='채팅방'
            className='joinInput mt-20'
            type='text'
            onChange={(event) => setRoom(event.target.value)}
          />
        </div>
        <Link
          onClick={(e) => (!name || !room ? e.preventDefault() : null)}
          to={`/chat?name=${name}&room=${room}`}
        >
          <button className={'button mt-20'} type='submit'>
            가입
          </button>
        </Link>
      </div>
    </div>
  )
}

export default Join

 

 

Components 폴더에 Chat, Join 폴더를 새로 만들어 각각의 js 파일에 넣어주고 아래의 css파일을 다운로드하여 넣어준다!

 

Chat.css
0.00MB
Join.css
0.00MB

 

App.js에 저장? 만 눌러줘도 자동적으로 localhost:3000에 적용이 된다.

 

join.css가 적용된 모습을 확인할 수 있다.

 

 

Chat.js에 가서 코드를 수정하기전 터미널에서 설치할 것이 있다. 

 

클라이언트 쪽에서 설치해야한다!

 

클라이언트 쪽에서의 socket 설치

 

이모티콘 사용하기 위한 설치

 

버튼을 누르면 다시 최신으로 이동

 

components 폴더에 InfoBar, Input, Messages, TextContainer 폴더를 추가한다.

 

InfoBar 폴더 안에 InfoBar.js파일을 생성한다.

 

Input폴더 안에 Input.js파일을 생성한다.

 

Messages 폴더 안에 Message 폴더를 생성하고 각각 js 파일을 생성한다.

 

TextContainer 폴더에 TextContainer.js를 만들어준다. 

 

각각 만든 js 파일에 rafce + tab을 눌러 파일 이름을 써준다.

 

나중에 출력됬을때 어떤 파일이 떴는지 알기 위함
InfoBar.css
0.00MB
Input.css
0.00MB
Message.css
0.00MB
Messages.css
0.00MB
TextContainer.css
0.00MB

 

각각의 css 파일을 아까와 같이 같은 이름폴더에 넣어준다!

 

복잡하지만 적용한 모습이다.

 

Chat.js에 가서 코드를 추가한다.

import React, { useState, useEffect } from 'react'
import queryString from 'query-string'
import io from 'socket.io-client'
import './Chat.css'
import InfoBar from '../InfoBar/InfoBar'
import Messages from '../Messages/Messages'
import Input from '../Input/Input'
import TextContainer from '../TextContainer/TextContainer'
const ENDPOINT = 'http://localhost:5000'
let socket

const Chat = ({ location }) => {
  const [name, setName] = useState('')
  const [room, setRoom] = useState('')
  const [users, setUsers] = useState('')
  const [message, setMessage] = useState('')
  const [messages, setMessages] = useState([])
  useEffect(() => {
    const { name, room } = queryString.parse(location.search)
    socket = io(ENDPOINT)

    setRoom(room)
    setName(name)
    socket.emit('join', { name, room }, (error) => {
      if (error) {
        alert(error)
      }
    })
  }, [ENDPOINT, location.search])
  useEffect(() => {
    //로딩 될때만 실행
    socket.on('message', (message) => {
      setMessage((message) => [...messages, message])
    })
    socket.on('roomData', ({ users }) => {
      setUsers(users)
    })
  }, [])
  const sendMessage = (event) => {
    event.preventDefault()
    if (message) {
      socket.emit('sendMessage', message, () => setMessage(''))
    }
  }
  return (
    <div className='outerContainer'>
      <div className='container'>
        <InfoBar room={room} />
        <Messages messages={messages} name={name} />
        <Input
          message={message}
          setMessage={setMessage}
          sendMessage={sendMessage}
        />
      </div>
      <TextContainer users={users} />
    </div>
  )
}

export default Chat

 

 

server/index.js 가서 통신이 되는지 코드를 수정해준다.

const express = require('express')
const socketio = require('socket.io')
const http = require('http')

const cors = require('cors')
const router = require('./router')

const PORT = process.env.PORT || 5000

const app = express()
const server = http.createServer(app)
const io = socketio(server)
app.use(cors())
app.use(router)
io.on('connection', (socket) => {
  console.log('새로운 connectoin이 발생하였습니다.')
  socket.on('join', ({ name, room }, callback) => {})
  socket.on('disconnect', () => {
    console.log('유저가 떠났어요.')
  })
})
server.listen(PORT, () => console.log(`서버가 ${PORT} 에서 시작되었어요`))

 

server/ router.js를 생성한다.

 

router.js

const express = require('express')
const router = express.Router()

router.get('/', (req, res) => {
  res.send({ response: 'Server is up and running' }).status(200)
})

module.exports = router

 

터미널에 cors와 nodemon을 설치해준다.

 

라이브로 계속 업데이트

 

package.json에 사진에 표시한 start 부분을 추가한다. 

 

 

서버를 돌린다!

 

 

서버가 연결됨을 확인하는데 콘솔창에 오류가 가득하였다.

 

밑의 사진처럼 package.json을 바꿔준다.

 

 

가입을 눌렀을때 표시한 console창에 표시한 글이 떠야 한다.

 

 

혹시나 바꿔도 오류가 뜬다면 node_modules를 삭제하면 되는데 아래 블로그에 상세히 설명했으니

 

2021.06.07 - [Tip] - [React] Cannot find module 'socket.io' 해결법 - 2

 

[React] Cannot find module 'socket.io' 해결법 - 2

2021.06.04 - [FRONT-END/React] - [React] 리액트 & socket.io 기반 채팅 어플리케이션 만들기 - 2 [React] 리액트 & socket.io 기반 채팅 어플리케이션 만들기 - 2 1탄을 보지 않고 2탄부터 오셨다면 꼭 보고 오..

hello-ming.tistory.com

 

여기로 가면 해결이 될것이다!

728x90
반응형
728x90
반응형

https://www.youtube.com/watch?v=ZwFA3YMfkoc 

https://github.com/adrianhajdin/project_chat_application

 

adrianhajdin/project_chat_application

This is a code repository for the corresponding YouTube video. In this tutorial we are going to build and deploy a real time chat application. Covered topics: React.js, Node.js, Express.js, and Soc...

github.com

 

이 영상을 보며 공부하고 따라 해 보려고 한다! 아 실행하기 앞서 node가 설치되어있어야 한다.

 

과정을 따라 하며 실행한 것을 블로그에 상세히 올리는 것이니 따라 해도 괜찮을 것이다. 

 

영상을 참고하되 이해하기 편하게 조금씩 코드를 바꾸기도 할 것이다!

 


Visual Studio Code에서 만들 파일을 생성하고 연결해준다.

 

나는 c:에 nodeExam 파일에 reactChatting 파일을 만들어서 연결해주었다.

 

client라는 react app을 생성해라

 

 

client라는 이름으로 react app이 생성됨을 확인할 수 있다.

 

console 차에도 설치됐다고 npm start 실행하라고 뜨는데 말 그대로 해줘야 한다! 그럼 서버와 연결이 된다.

 

 

 

localhost:3000으로 react 서버가 연결되었다.

 

 

터미널에 react-router-dom을 설치한다.

 

package.json에 설치됨을 확인할 수 있다.

 

 

App.js를 수정해준다.

import React from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Chat from './components/Chat'
import Join from './components/Join'

const App = () => {
  return (
    <Router>
      <Route path='/' component={Join} />
      <Route path='/chat' component={Chat} />
    </Router>
  )
}

export default App

 

Chat.js

import React from 'react'

export const Chat = () => {
    return (
        <div>
            채팅
        </div>
    )
}

export default Chat

 

Join.js

import React from 'react'

const Join = () => {
    return (
        <div>
            가입
        </div>
    )
}

export default Join

 

터미널을 열어준다.

 

 

 

서버 확인할 수 있다.

 

init : 초기화

 

 

server 파일 안에 package.json이 생성되었다.

 

server 폴더에 index.js 파일도 만들어 준다.

 

express 설치하기

 

소켓통신을 위해 라이브러리를 설치한다.

socket.io 설치하기

 

설치가 완료됐으면 아까 만든 index.js에 내용을 추가한다.

 

index.js

const express = require('express')
const socketio = require('socket.io')
const http = require('http')

const PORT = process.env.PORT || 5000

const app = express();
const server = http.createServer(app)
const io = socketio(server)
server.listen(PORT,()=>console.log(`서버가 ${PORT} 에서 시작되었어요`))

 

 

서버가 5000번 포트에서 index.js 를돌린다.

 

 

/chat 추가

 

서버와 연결이 되었다. 만약 나오지 않는다면 터미널에 

npm run start

 

하면 될 것이다.

728x90
반응형
728x90
반응형

 

https://gist.github.com/saleph/a301957b16dff7ad2892

 

[qt5] grid layout - calculator skeleton

[qt5] grid layout - calculator skeleton. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

 

전 포스팅인 PT Designer를 이용하여 계산기를 만들면서 구글링을 통해 위 사이트를 알게 되었다.

 

사이트에 있는 코드는 grid 계산기의 layout만 있었다. 이 코드를 이용하여 계산기의 기능을 구현하고자 한다.

 

def init_ui(self): 까지는 사이트에 있던 코드의 내용이고

 

def func_a는 내가 계산기의 기능을 추가한 것이다!

 

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, QPushButton, QApplication, QPlainTextEdit, QLabel)

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.str =''
        self.label =QLabel();
        self.init_ui()

    def init_ui(self):
        grid = QGridLayout()
        self.setLayout(grid)

        names = ['Cls', 'Bck', '', 'Close',
                 '7', '8', '9', '/',
                 '4', '5', '6', '*',
                 '1', '2', '3', '-',
                 '0', '.', '=', '+']

        positions = [(i,j) for i in range(5) for j in range(4)]

        for position, name in zip(positions, names):
            if name == '' : continue
            btn = QPushButton(name)
            btn.clicked.connect(self.func_a)
            grid.addWidget(btn, *position)
        grid.addWidget(self.label)
        self.move(300,150)
        self.setWindowTitle('Calculator')
        self.show()
        self.str=""

    def func_a(self,x) -> None:
        sender = self.sender()  # 어떤 콤포넌트 또는 위젯에서 어떤 signal이 발생했는가?
        self.str = self.str + sender.text()

        self.label.setText(self.str)
        result=[]
        first_operand = 0

        if 'C' in self.str: #비우기
            self.label.clear()
            self.str = '' #문자열 내용 비우기

        for i in list(self.str):
            result_str = ''.join(result)
            if i == '=': # =일 경우 계산 결과를 label에 적용
                print("결과는 =",i, 'result :', result)
                print('결과는 ',result_str)
                print('비어있나', first_operand)
                print('계산 결과는', int(result_str)+first_operand)
                if '+' in self.str:
                    self.label.setText(str(int(result_str) + first_operand))
                if '-' in self.str:
                    self.label.setText(str(first_operand - int(result_str)))
                if '*' in self.str:
                    self.label.setText(str(first_operand * int(result_str)))
                if '/' in self.str:
                    self.label.setText(str(first_operand / int(result_str)))

            elif i in ['+','-','*','/']:
                first_operand += int(result_str)
                print('덧셈 누르면',result_str)
                print(i)
                result=[]

            else:
                result.append(i)
                print(i, '결과 : ',result)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

 

실행화면

 

2/3 입력

 

= 누른 순간 0.6666666666이 계산되었다.

728x90
반응형
728x90
반응형

https://www.geeksforgeeks.org/building-calculator-using-pyqt5-in-python/

 

Building Calculator using PyQt5 in Python - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

위의 사이트는 계산기를 구현하고 작동영상까지 있다.

 

이 사이트를 참고해서 만들었고 그냥 복붙이 아닌 Qt Designer에서 만들어서 사이트에 있는 연산 메소드를 참고하여 만들었다!

 

Qt Designer에서 계산기 모양 틀을 만들어 준다.

 

이 파일을 저장하면 .ui가 되는데 파이참에서 코드를 수정할 거라 .py로 변환해 주어야 한다.

 

변환 방법은 

 

2021.06.02 - [FRONT-END/PyQT] - [PyQT] PyQt5 및 Qt Designer 설치 / .ui -> .py 변환

 

[PyQT] PyQt5 및 Qt Designer 설치 / .ui -> .py 변환

PyQt5 설치 pip install pyqt5 Pyside2 설치 pip install pyside2 Pyside2를 설치하셨으면 Qt Designer가 자동으로 설치되어있다. designer.exe를 바로가기로 만들어두면 사용하기 편해진다. UI 파일을 PY 파일..

hello-ming.tistory.com

 

위 사이트에 정리해 놓아서 들어가 보면 쉽게 따라할 수 있을 것이다.

 

링크 안가도 이거 따라하면 된다..ㅎㅎ

 

 

calculator.py를 파이참에 띄우면 디자인한 계산기 모양 그대로 뜬다.

 

여기서 연산 (+,-,*,/) 하도록 메서드는 위 사이트에서 참고하여 붙여주었고 나머지 숫자들을 연결시켜 주었다.

 

from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(360, 370)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(5, 150, 80, 40))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(95, 150, 80, 40))
        self.pushButton_2.setObjectName("pushButton_2")
        self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_3.setGeometry(QtCore.QRect(185, 150, 80, 40))
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_5 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_5.setGeometry(QtCore.QRect(185, 200, 80, 40))
        self.pushButton_5.setObjectName("pushButton_5")
        self.pushButton_6 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_6.setGeometry(QtCore.QRect(5, 200, 80, 40))
        self.pushButton_6.setObjectName("pushButton_6")
        self.pushButton_7 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_7.setGeometry(QtCore.QRect(95, 200, 80, 40))
        self.pushButton_7.setObjectName("pushButton_7")
        self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_4.setGeometry(QtCore.QRect(185, 250, 80, 40))
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_8 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_8.setGeometry(QtCore.QRect(95, 300, 80, 40))
        self.pushButton_8.setObjectName("pushButton_8")
        self.pushButton_9 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_9.setGeometry(QtCore.QRect(5, 300, 80, 40))
        self.pushButton_9.setObjectName("pushButton_9")
        self.pushButton_10 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_10.setGeometry(QtCore.QRect(5, 250, 80, 40))
        self.pushButton_10.setObjectName("pushButton_10")
        self.pushButton_11 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_11.setGeometry(QtCore.QRect(185, 300, 80, 40))
        self.pushButton_11.setObjectName("pushButton_11")
        self.pushButton_12 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_12.setGeometry(QtCore.QRect(95, 250, 80, 40))
        self.pushButton_12.setObjectName("pushButton_12")
        self.pushButton_13 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_13.setGeometry(QtCore.QRect(275, 150, 80, 40))
        self.pushButton_13.setObjectName("pushButton_13")
        self.pushButton_14 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_14.setGeometry(QtCore.QRect(275, 250, 80, 40))
        self.pushButton_14.setObjectName("pushButton_14")
        self.pushButton_15 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_15.setGeometry(QtCore.QRect(275, 200, 80, 40))
        self.pushButton_15.setObjectName("pushButton_15")
        self.pushButton_16 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_16.setGeometry(QtCore.QRect(275, 300, 80, 40))
        self.pushButton_16.setObjectName("pushButton_16")
        self.pushButton_17 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_17.setGeometry(QtCore.QRect(5, 100, 200, 40))
        self.pushButton_17.setObjectName("pushButton_17")
        self.pushButton_18 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_18.setGeometry(QtCore.QRect(210, 100, 145, 40))
        self.pushButton_18.setObjectName("pushButton_18")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(5, 5, 350, 70))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(15)
        self.label.setFont(font)
        self.label.setStyleSheet("QLabel{ \n"
"            border : 2px solid black;\n"
"            background : white;\n"
"            }")
        self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTop|QtCore.Qt.AlignTrailing)
        self.label.setWordWrap(True)
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 360, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "pyqt 계산기"))
        self.pushButton.setText(_translate("MainWindow", "1"))
        self.pushButton_2.setText(_translate("MainWindow", "2"))
        self.pushButton_3.setText(_translate("MainWindow", "3"))
        self.pushButton_5.setText(_translate("MainWindow", "6"))
        self.pushButton_6.setText(_translate("MainWindow", "4"))
        self.pushButton_7.setText(_translate("MainWindow", "5"))
        self.pushButton_4.setText(_translate("MainWindow", "9"))
        self.pushButton_8.setText(_translate("MainWindow", "."))
        self.pushButton_9.setText(_translate("MainWindow", "0"))
        self.pushButton_10.setText(_translate("MainWindow", "7"))
        self.pushButton_11.setText(_translate("MainWindow", "/"))
        self.pushButton_12.setText(_translate("MainWindow", "8"))
        self.pushButton_13.setText(_translate("MainWindow", "*"))
        self.pushButton_14.setText(_translate("MainWindow", "+"))
        self.pushButton_15.setText(_translate("MainWindow", "-"))
        self.pushButton_16.setText(_translate("MainWindow", "="))
        self.pushButton_17.setText(_translate("MainWindow", "Clear"))
        self.pushButton_18.setText(_translate("MainWindow", "Del"))
        self.label.setText(_translate("MainWindow", "TextLabel"))

        # adding action to each of the button
        self.pushButton_15.clicked.connect(self.action_minus)
        self.pushButton_16.clicked.connect(self.action_equal)
        self.pushButton_9.clicked.connect(self.action0)
        self.pushButton.clicked.connect(self.action1)
        self.pushButton_2.clicked.connect(self.action2)
        self.pushButton_3.clicked.connect(self.action3)
        self.pushButton_6.clicked.connect(self.action4)
        self.pushButton_7.clicked.connect(self.action5)
        self.pushButton_5.clicked.connect(self.action6)
        self.pushButton_10.clicked.connect(self.action7)
        self.pushButton_12.clicked.connect(self.action8)
        self.pushButton_4.clicked.connect(self.action9)
        self.pushButton_11.clicked.connect(self.action_div)
        self.pushButton_13.clicked.connect(self.action_mul)
        self.pushButton_14.clicked.connect(self.action_plus)
        self.pushButton_8.clicked.connect(self.action_point)
        self.pushButton_17.clicked.connect(self.action_clear)
        self.pushButton_18.clicked.connect(self.action_del)

    def action_equal(self):

        # get the label text
        equation = self.label.text()

        try:
            # getting the ans
            ans = eval(equation)

            # setting text to the label
            self.label.setText(str(ans))

        except:
            # setting text to the label
            self.label.setText("Wrong Input")

    def action_plus(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + " + ")

    def action_minus(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + " - ")

    def action_div(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + " / ")

    def action_mul(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + " * ")

    def action_point(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + ".")

    def action0(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "0")

    def action1(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "1")

    def action2(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "2")

    def action3(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "3")

    def action4(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "4")

    def action5(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "5")

    def action6(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "6")

    def action7(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "7")

    def action8(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "8")

    def action9(self):
        # appending label text
        text = self.label.text()
        self.label.setText(text + "9")

    def action_clear(self):
        # clearing the label text
        self.label.setText("")

    def action_del(self):
        # clearing a single digit
        text = self.label.text()
        print(text[:len(text)-1])
        self.label.setText(text[:len(text)-1])

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

 

참고할 점은 design을 이용한거라 button의 번호를 맞춰주는게 중요하다.

 

 

728x90
반응형
728x90
반응형

 

이번 툴바를 만들 때는 파이썬의 가변인자를 응용한 것이라 이해를 돕기 위해 파이썬의 가변인자 예제를 먼저 보여준 후 툴바를 만들것이다.

 

나는 파이참에서 실행하였다.

 

def my_sum(*integers):
    result=0
    for x in integers:
        result+=x
    return result

def concatenate(**kwargs):
    result=""
    print("딕셔너리",kwargs)
    for arg in kwargs.values():
        result += arg
    return result

print(my_sum(1,2,3,4)) #가변인자
print(concatenate(a="Real", b="파이썬", c="은", d="훌륭하다", e="!"))

 

이제 툴바를 만들어 보자

 

import sys
from PyQt5.QtCore import Qt

from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QLabel, QToolBar, QStatusBar

class MainWindow(QMainWindow):
     def __init__(self, *args, **kwargs):
         super(MainWindow, self).__init__(*args, **kwargs)
         self.setWindowTitle("나의 놀라운 앱")
         label = QLabel("This is 놀랍다")
         label.setAlignment(Qt.AlignCenter)
         self.setCentralWidget(label)

         toolbar = QToolBar("나의 메인 툴바")
         self.addToolBar(toolbar)

         button_action = QAction("당신의 버튼",self)
         button_action.setStatusTip("이것은 당신의 버튼이에요")
         button_action.triggered.connect(self.onMyToolBarButtonClick)
         toolbar.addAction(button_action)
         self.setStatusBar(QStatusBar(self))

     def onMyToolBarButtonClick(self,s):
        print("눌렸다 : ",s)

if __name__ == "__main__":
    qApp = QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(qApp.exec_())

self는  mainWindow안에 멤버변수나 메서드를 뜻한다.

 

label 객체는 self가 없는데 넣어도 잘 된다!

 

self의 유무의 차이는 self가 없으면 지역변수가 되므로 다른 곳에서 쓸 수 없다. 자바의 this 느낌

 

멤버변수면 this와 비슷한 self를 줘야한다!

 

이 툴바를 실행하면 

당신의 버튼에 커서를 위치시키면 statebar 가 뜬다.

 

버튼을 누르면 console창에 뜬다.

 

 

728x90
반응형
728x90
반응형

PyCharm(파이참)에서 PyQT를 실행하였고

 

위젯을 생성하여 버튼을 누르면 함수를 호출하여 QMessageBox를 띄우는 것을 해볼 것이다.

 

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QMessageBox

def dialog():
    a = QMessageBox()
    a.setText("여기에 출력되요")
    a.setDetailedText("상세 항목이 나와요")
    a.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
    a.exec_()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w= QWidget()
    w.resize(300,300)
    w.setWindowTitle("안녕 컴퓨터")
    label = QLabel(w)
    label.setText("여기는 라벨이에요")
    label.move(100,130)
    label.show()
    btn = QPushButton(w) #위젯 집어넣기
    btn.setText("여기는 푸시 버튼")
    btn.move(110,150) #버튼의 위치 이동
    btn.clicked.connect(dialog) #btn이 눌리면 dialog 함수 호출
    btn.show() #버튼을 보여줌
    w.show() # 중요 window는 기본값이 hidden이라 show 해야함
    sys.exit(app.exec_()) # 이상태는 이벤트 루프가 돌고있다.

라벨과 푸시버튼

 

버튼을 누르면 QMessageBox가 띄어진다.

728x90
반응형
728x90
반응형

파이참에서 pyqt를 적용하여 화면을 띄어보자

 

import sys
from PyQt5.QtWidgets import QApplication, QWidget

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w= QWidget()
    w.resize(300,300)
    w.setWindowTitle("안녕 컴퓨터")
    w.show()
    sys.exit(app.exec_())

[ 코드 설명 ]

 

resize - 위젯의 크기를 정함 (x축, y축)

 

w.show() # 중요하다.!  window는 기본값이 hidden이라 show 해야한다.

 

sys.exit(app.exec_()) # 이상태는 이벤트 루프가 돌고있다.

 

 

728x90
반응형
728x90
반응형

QPalette 클래스는 각 위젯 상태에 대한 색상 그룹을 포함한다.

 

import sys
from PyQt5.QtCore import Qt

from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QMessageBox, QGridLayout

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle("Fusion")
    qp = QPalette()
    qp.setColor(QPalette.ButtonText, Qt.black)
    qp.setColor(QPalette.Window, Qt.black)
    qp.setColor(QPalette.Button, Qt.gray)
    #만든것을 앱에 추가
    app.setPalette(qp)

    w= QWidget()
    grid= QGridLayout(w)
    grid.addWidget(QPushButton("버튼 1"), 0,0) #0행 0렬
    grid.addWidget(QPushButton("버튼 2"), 0,1) #0행 10렬
    grid.addWidget(QPushButton("버튼 3"), 1,0) #1행 0렬
    grid.addWidget(QPushButton("버튼 4"), 1,1) #1행 1렬

    w.show() # 중요 window는 기본값이 hidden이라 show 해야함
    sys.exit(app.exec_()) # 이상태는 이벤트 루프가 돌고있다.

728x90
반응형

+ Recent posts