Имеется пустой файл (0 байт). Почему feof() не возвращает true?
Ответ
Представьте, что поток чтения - это чёрный ящик (а в общем так оно и есть). Только попробовав прочитать очередной байт и получив шиш с маслом, узнаешь, что файл кончился...
Имеется пустой файл (0 байт). Почему feof() не возвращает true?
Представьте, что поток чтения - это чёрный ящик (а в общем так оно и есть). Только попробовав прочитать очередной байт и получив шиш с маслом, узнаешь, что файл кончился...
Добрый день, создал программу которая забирает данные из БД и выводит их в qtableWidget_1 в котором выведенные строки можно отметить с помощью Check Box. Рядом есть qtablewidget_2 куда отмеченные строки нужно скопировать, подскажите как такое можно реализовать ?
Сам код вывода запроса из БД.
void MainWindow::on_pushButton_2_clicked()
{
ui->tableWidget->setColumnCount(5); // Указываем число колонок
ui->tableWidget->setShowGrid(true); // Включаем сетку
ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); // Разрешаем выделение только одного элемента
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);// Разрешаем выделение построчно
//ui->tableWidget->setHorizontalHeaderLabels(headers);// Устанавливаем заголовки колонок
ui->tableWidget->horizontalHeader()->setStretchLastSection(false);// Растягиваем последнюю колонку на всё доступное пространство
// ui->tableWidget->hideColumn(0);// Скрываем колонку под номером 0
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);//Запрещаем редактировать данные в полях таблицы
// Создаём запрос для для выборки записей из базы данных
QSqlQuery query = QSqlQuery(db);
if (!query.exec("SELECT * FROM mytable"))
{
QMessageBox::information(this,"Окно информации","Не удалось выполнить запрос возможно нет соеденеия с базой данных.");
qDebug() << query.lastError().databaseText();
qDebug() << query.lastError().driverText();
return;
}else{
/* Выполняем заполнение QTableWidget записями с помощью цикла
* */
for(int i = 0; query.next(); i++){
ui->tableWidget->insertRow(i);// Вставляем строку
/* Устанавливаем в первую колонку id забирая его из результата SQL-запроса
* Эта колонка будет скрыта
* */
ui->tableWidget->setItem(i,0, new QTableWidgetItem(query.value(0).toString()));
QTableWidgetItem *item = new QTableWidgetItem();// Создаём элемент, который будет выполнять роль чекбокса
item->data(Qt::CheckStateRole);
/* Проверяем, на статус нечетности, если нечетное устройство, то
* выставляем состояние чекбокса в Checked, иначе в Unchecked
* */
if(query.value(1).toInt() == 1){
item->setCheckState(Qt::Checked);
} else {
item->setCheckState(Qt::Unchecked);
}
ui->tableWidget->setItem(i,0, item);// Устанавливаем чекбокс во вторую колонку
// Забираем все данные из результата запроса и устанавливаем в остальные поля
ui->tableWidget->setItem(i,1, new QTableWidgetItem(query.value(1).toString()));
ui->tableWidget->setItem(i,2, new QTableWidgetItem(query.value(2).toString()));
ui->tableWidget->setItem(i,3, new QTableWidgetItem(query.value(3).toString()));
ui->tableWidget->setItem(i,4, new QTableWidgetItem(query.value(4).toString()));
ui->tableWidget->setItem(i,5, new QTableWidgetItem(query.value(5).toString()));
}
ui->tableWidget->resizeColumnsToContents();
db.close();
}
}
Задача решена:
ui->tableWidget_1->setItem(i,1, new QTableWidgetItem(ui->tableWidget->item(i, 1)->text()));
как вариант можно использовать так же данную конструкцию
ui->tableWidget_1->setItem(i,1, ui->tableWidget->item(i, 1)->clone());
При создании файла/директории в локальном репозитории git, файл копируется во все ветки, а не в ту в которой создается (через консоль и редактор). Как этого избежать?
вообще, создаёте вы файлы/каталоги не в репозитории/хранилище, а в рабочем каталоге (working directory/tree).
в хранилище файлы (точнее, их содержимое) «попадают» только после команды git commit
при переключении между ветками/коммитами программа git «вычисляет», какие изменения следует внести в рабочий каталог:
файлы/каталоги, которые есть в текущей ветке/коммите, но отсутствуют в той, на которую переключаетесь, удаляются;
файлы/каталоги, которых нет в текущей ветке/коммите, но которые присутствуют в той, на которую переключаетесь, извлекаются из содержимого хранилища;
аналогично извлекается и содержимое файлов, которое отличается: в текущей ветке/коммите — одно, в той, на которую переключаетесь — другое.
все же остальные файлы/каталоги при переключении между ветками/коммитами вообще никак не будут затронуты.
это относится и к тем файлам/каталогам, которых нет ни в текущей ветке/коммите, ни в той, на которую переключаетесь.
Как этого избежать?
пока вы не сохранили эти файлы/каталоги внутри хранилища, программа git, по крайней мере, выполняя команду checkout, не будет «касаться» таких «неотслеживаемых» файлов/каталогов внутри рабочего каталога.
так что краткий ответ: никак не избежать. так задумано.
Как получить hwnd окна по имени процесса. Вот например я могу получить hwnd по имени окна
hwnd = win32gui.FindWindow(None, "Notepad")
Можно ли так же легко получить hwnd по имени процесса?
Совсем просто не получится, потому что:
Может быть несколько процессов с одним именем (например, можно открыть несколько окон Блокнота).
У процесса может быть несколько окон
Поэтому сначала нужно получить список процессов с заданными именем файла (или для простоты первый попавшийся процесс, подходящий по этому условию), потом список окон для данного процесса (процессов).
1. Получаем список процессов, у которых имя файла равно notepad.exe
Можно воспользоваться пакетом psutil
import psutil
# Список процессов с именем файла notepad.exe:
notepads = [item for item in psutil.process_iter() if item.name() == 'notepad.exe']
print(notepads) # [
# Просто pid первого попавшегося процесса с именем файла notepad.exe:
pid = next(item for item in psutil.process_iter() if item.name() == 'notepad.exe').pid
# (вызовет исключение StopIteration, если Блокнот не запущен)
print(pid) # 4416
2. Получаем список окон процесса с заданным pid
Чтобы получить список окон процесса, можно воспользоваться функцией EnumWindows
Например, нужно получить все окна процесса с ID 4416:
import win32gui
import win32process
def enum_window_callback(hwnd, pid):
tid, current_pid = win32process.GetWindowThreadProcessId(hwnd)
if pid == current_pid and win32gui.IsWindowVisible(hwnd):
windows.append(hwnd)
# pid = 4416 # pid уже получен на предыдущем этапе
windows = []
win32gui.EnumWindows(enum_window_callback, pid)
# Выводим заголовки всех полученных окон
print([win32gui.GetWindowText(item) for item in windows])
Вывод:
['Безымянный — Блокнот']
Если в Блокноте открыть еще настройку параметров страницы, то список будет такой:
['Параметры страницы', 'Безымянный — Блокнот']
Мне нужно из Bitmap создать картинку формата *.png или *.jpg Помогите!
Помог метод Image.Save (String, ImageFormat)
Bitmap PictureImg = new Bitmap(2560, 1920);
PictureImg.Save("img.png", System.Drawing.Imaging.ImageFormat.Png);
Gitlab pages позволяет публиковать index.html туда.
Есть свой развернутый GitLab последней версии. что мне нужно делать, чтобы я смог использовать свой основной DNS и опубликовал также сайт?
Нужно установить и запустить GitLab Pages daemon — это их собственный вебсервер. Он может быть установлен как на одном хосте с гитлабом, так и на отдельном.
Поставляется он в пакете Omnibus или отдельно.
Подробные инструкции есть в GitLab Pages configuration
Также можно установить и сконфигурировать с помощью роли Ansible debops.ansible-gitlab
После выполнения, кода я получаю черно-белое изображение, которое состоит из двух измерений (ширина высота) и само значение от 0 до 255 - от черного до белого. Для дальнейшего использования мне необходимо конвертировать его в rgb8. Например функция cv2.floodFill не принимает изображение, которое я получил. Вот сам код:
import sys
import cv2
import numpy as np
import time
from matplotlib import pyplot as plt
img = cv2.imread('2.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# noise removal
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2)
# sure background area
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.55 * dist_transform.max(), 255, 0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+10
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0
markers = cv2.watershed(img, markers)
img[markers == -1] = [255, 0, 0]
cv2.imwrite('6.jpg', markers)
Есть ли возможность конвертировать markers в нормальное изображение?
Команда
np.ndarray.astype(np.uint8)
помогла
Здравствуйте
У меня в форме авторизации после всех проверок идет вот такая запись
$_SESSION['user'] = $user;
в сессию сохраняется весь объект $user, то есть логин, пароль и полностью все данные с записи таблицы.
если записать так:
$_SESSION['user'] = $user['id'];
в сессию сохраниться только его id
Вопрос:
как сохранить в сессию id,login и image? как правильно нужно написать?
прошу помощи в реализации.
Например так:
$_SESSION['user'] = [
'id' => $user['id'],
'login' => $user['login'],
'image' => $user['image'],
];
В браузере все понятно, у него заранее есть список вшитых сертификатов CA, которыми он проверяет сертификат сервера... Но как происходит проверка в мобильных приложениях? Или, допустим, когда я отправляю запрос, допустим, через BurpSuite?
Общие принципы SSL (а точнее, инфраструктуры ключей) продолжают работать и в контексте мобильных приложений. Набор CA (или, по-русски, ЦС – центров сертификации):
может быть размещен в ОС (чаще всего, т. к. он используется по умолчанию [обычно]).
может поставляться с приложением (что не такая уж редкость, см. Firefox).
может отсутствовать вовсе, если клиент заранее знает публичный ключ сервера сам, или может попросить пользователя проверить отпечаток ключа в интерфейсе (привет, SSH!), или просто плевать хотел на безопасность (и такое бывает! ¯\_(ツ)_/¯).
Может использоваться несколько вариантов сразу. Например, Яндекс.Браузер использует гибрид: он рассчитывает на системное хранилище, но отпечатки (хэши) сертификатов ЦСов оттуда сравнивает с известными ему (за уточнение механизма спасибо Abyx). Их немного, поэтому зашить в бинарник не проблема. Таким образом ЯБ пытается предупреждать ситуации, в которых соединение пользователя компрометируется через сторонний ЦС, установленный в систему без его ведома.
Так что, как видите, SSL довольно хорошо гнётся под разные ситуации.
Но реально этим богатством редко пользуются.
В подавляющем большинстве случаев сервер имеет ключ, заверенный известным ЦС, а клиент имеет только пачку известных ЦС в ОС. Сервер предоставляет доказательства, указывающие через известные ЦС на подлинность своего ключа. Так клиент понимает, что это тот самый сервер.
Есть имитация input type="range" на javascript.
function Range(container) {
this.container = container;
if (!this.container) return;
this.inputMin = container.querySelector('[data-type=input-min]');
this.inputMax = container.querySelector('[data-type=input-max]');
this.minValue = parseFloat(container.querySelector('[data-type=min-val]').textContent.replace(/\s/g, ''));
this.maxValue = parseFloat(container.querySelector('[data-type=max-val]').textContent.replace(/\s/g, ''));
this.inner = container.querySelector('[data-type=range-inner-element]');
this.valuesElem = container.querySelector('[data-type=range-element]');
this.minBtn = container.querySelector('[data-type=min-btn]');
this.maxBtn = container.querySelector('[data-type=max-btn]');
//console.log(this);
this.init();
}
Range.prototype.drag = function(event) {
function move(event) {
var left = event.pageX - elemX - boxX;
if (elem == this.minBtn) {
this.inner.style.left = elem.offsetLeft + elem.offsetWidth / 2 + 'px';
if (left < 0) {
left = 0;
}
if (left > this.maxBtn.offsetLeft - elem.offsetWidth) {
left = this.maxBtn.offsetLeft - elem.offsetWidth;
}
} else if (elem == this.maxBtn) {
this.inner.style.right = elem.offsetLeft - elem.offsetWidth / 2 + 'px';
if (left < this.minBtn.offsetLeft + elem.offsetWidth) {
left = this.minBtn.offsetLeft + elem.offsetWidth;
}
if (left > this.valuesElem.offsetWidth - elem.offsetWidth) {
left = this.valuesElem.offsetWidth - elem.offsetWidth;
}
}
elem.style.left = left + 'px';
this.inner.style.width = this.maxBtn.offsetLeft - this.minBtn.offsetLeft + 'px';
}
function removeMove() {
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', removeMove);
}
if (event.target == this.minBtn || event.target == this.maxBtn) {
var elem = event.target;
var elemX = event.pageX - elem.getBoundingClientRect().left;
var boxX = this.valuesElem.getBoundingClientRect().left;
var coord = event.target.offsetLeft;
move = move.bind(this);
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', removeMove);
event.target.ondragstart = function() {
return false;
};
}
}
Range.prototype.setValue = function() {
this.inputMin.value = this.minValue;
this.inputMax.value = this.maxValue;
}
Range.prototype.init = function() {
this.inner.style.left = this.minBtn.offsetLeft + this.minBtn.offsetWidth / 2 + 'px';
this.inner.style.right = this.maxBtn.offsetLeft - this.maxBtn.offsetWidth / 2 + 'px';
this.setValue();
this.valuesElem.addEventListener('mousedown', this.drag.bind(this));
}
var range = new Range(document.querySelector('[data-type=range]'));
.filters_section_list {
width: 300px;
list-style: none
}
.filters_section_item .range {
height: 6px;
background-color: #AEAEAE;
border-radius: 4px;
position: relative;
}
.filters_section_item .range_inner {
height: inherit;
background-color: #FD2016;
}
.filters_section_item .range_btn {
width: 18px;
height: 18px;
border-radius: 50%;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.6);
position: absolute;
top: -7px;
background-color: #fff;
cursor: pointer;
}
.filters_section_item .range_inner {
position: absolute;
width: 100%;
}
.filters_section_item .range_btn[data-type=min-btn] {
left: 0;
}
.filters_section_item .range_btn[data-type=max-btn] {
left: 100%;
}
.filters_section_item .values {
overflow: hidden;
margin-top: 40px;
}
.filters_section_item .values .min-value {
float: left;
width: 35%;
text-align: left;
padding-bottom: 14px;
padding-left: 10px;
padding-right: 10px;
border-bottom: 1px solid #ACACAC;
}
.filters_section_item .values .max-value {
float: right;
width: 35%;
text-align: right;
padding-bottom: 14px;
padding-left: 10px;
padding-right: 10px;
border-bottom: 1px solid #ACACAC;
}
function Range(container) { this.container = container; if (!this.container) return; this.inputMin = container.querySelector('[data-type=input-min]'); this.inputMax = container.querySelector('[data-type=input-max]'); this.minValue = parseFloat(container.querySelector('[data-type=min-val]').textContent.replace(/\s/g, '')); this.maxValue = parseFloat(container.querySelector('[data-type=max-val]').textContent.replace(/\s/g, '')); this.inner = container.querySelector('[data-type=range-inner-element]'); this.valuesElem = container.querySelector('[data-type=range-element]'); this.minBtn = container.querySelector('[data-type=min-btn]'); this.maxBtn = container.querySelector('[data-type=max-btn]'); //console.log(this); this.init(); } Range.prototype.drag = function(event) { function move(event) { var left = event.pageX - elemX - boxX; var target; if (elem == this.minBtn) { this.inner.style.left = elem.offsetLeft + elem.offsetWidth / 2 + 'px'; if (left < 0) { left = 0; } if (left > this.maxBtn.offsetLeft - elem.offsetWidth) { left = this.maxBtn.offsetLeft - elem.offsetWidth; } target = this.container.querySelector('[data-type=min-val]'); } else if (elem == this.maxBtn) { this.inner.style.right = elem.offsetLeft - elem.offsetWidth / 2 + 'px'; if (left < this.minBtn.offsetLeft + elem.offsetWidth) { left = this.minBtn.offsetLeft + elem.offsetWidth; } if (left > this.valuesElem.offsetWidth - elem.offsetWidth) { left = this.valuesElem.offsetWidth - elem.offsetWidth; } target = this.container.querySelector('[data-type=max-val]'); } elem.style.left = left + 'px'; this.inner.style.width = this.maxBtn.offsetLeft - this.minBtn.offsetLeft + 'px'; target.innerText = this.minValue + (this.maxValue - this.minValue)*(left/this.valuesElem.offsetWidth); } function removeMove() { document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', removeMove); } if (event.target == this.minBtn || event.target == this.maxBtn) { var elem = event.target; var elemX = event.pageX - elem.getBoundingClientRect().left; var boxX = this.valuesElem.getBoundingClientRect().left; var coord = event.target.offsetLeft; move = move.bind(this); document.addEventListener('mousemove', move); document.addEventListener('mouseup', removeMove); event.target.ondragstart = function() { return false; }; } } Range.prototype.setValue = function() { this.inputMin.value = this.minValue; this.inputMax.value = this.maxValue; } Range.prototype.init = function() { this.inner.style.left = this.minBtn.offsetLeft + this.minBtn.offsetWidth / 2 + 'px'; this.inner.style.right = this.maxBtn.offsetLeft - this.maxBtn.offsetWidth / 2 + 'px'; this.setValue(); this.valuesElem.addEventListener('mousedown', this.drag.bind(this)); } var range = new Range(document.querySelector('[data-type=range]')); .filters_section_list { width: 300px; list-style: none } .filters_section_item .range { height: 6px; background-color: #AEAEAE; border-radius: 4px; position: relative; } .filters_section_item .range_inner { height: inherit; background-color: #FD2016; } .filters_section_item .range_btn { width: 18px; height: 18px; border-radius: 50%; box-shadow: 0 0 3px rgba(0, 0, 0, 0.6); position: absolute; top: -7px; background-color: #fff; cursor: pointer; } .filters_section_item .range_inner { position: absolute; width: 100%; } .filters_section_item .range_btn[data-type=min-btn] { left: 0; } .filters_section_item .range_btn[data-type=max-btn] { left: 100%; } .filters_section_item .values { overflow: hidden; margin-top: 40px; } .filters_section_item .values .min-value { float: left; width: 35%; text-align: left; padding-bottom: 14px; padding-left: 10px; padding-right: 10px; border-bottom: 1px solid #ACACAC; } .filters_section_item .values .max-value { float: right; width: 35%; text-align: right; padding-bottom: 14px; padding-left: 10px; padding-right: 10px; border-bottom: 1px solid #ACACAC; }
При программировании на java столкнулся с проблемой, что календарь не всегда правильно возвращает день недели. Пробовал использовать как Calendar, так и GregorianCalendar, но результат одинаковый.
Для примера:
GregorianCalendar calendar1 = new GregorianCalendar(196, 0, 1);
System.out.println(calendar1.get(GregorianCalendar.DAY_OF_WEEK));
Результатом в выводе будет 5, хотя по календарю: 01 января 196 - пятница, а значит мы должны были получить значение 6. Такая же проблема с годами:
1036 (1 января - воскресенье, а возвращает 5)
1316 (1 января - среда, а возвращает 5)
1456 (1 января - вторник, а возвращает 5)
и др.
Но иногда возвращает и правильные значения. Например:
GregorianCalendar calendar2 = new GregorianCalendar(1600, 0, 1);
System.out.println(calendar2.get(GregorianCalendar.DAY_OF_WEEK));
вернет 7, и по календарю это суббота.
Отвечу сам на собственный вопрос.
Такая неразбериха с календарями получилась из-за отличий Григорианского и Юлианского календарей. В Юлианском календаре високосный год наступает каждый год, который кратный 4, а в Григорианском - високосными считаются года, которые делятся на 4, но не кратные 100 (за исключением годов, которые делятся на 400). Это означает, что постепенно разница между этими календарями увеличивается на 3 дня каждые 400 лет.
Т.к. на Григорианский практически все страны перешли только с 1582 года, то до этого времени все ресурсы и языки программирования (помимо Java сравнивал еще с Python) по-своему высчитывают этот период.
Что касается Java, то, как я понял, до 1582 года включительно в языке используется Юлианский календарь, а с 1583 - Григорианский.
Как организовать движение картинок по path друг за другом, как угодно, только не друг на друге (задать координаты в цикле не получилось, где-то ошибаюсь..). Фрагмент кода:
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var W = window.innerWidth,
H = window.innerHeight;
canvas.width = W;
canvas.height = H;
var angle = 0;
var currentAngle = 0;
var TO_RADIANS = Math.PI / 180;
var particles = [];
var counter = 0;
var svg = document.getElementById("k9");//path из svg
var straightLength = svg.getTotalLength();
function Particle() {
this.radius = 20;
this.x = svg.getPointAtLength(straightLength).x;
this.y = svg.getPointAtLength(straightLength).y;
this.move = function() {
for ( var g = 0; g < particles.length; g++){
this.x = svg.getPointAtLength(counter*straightLength).x;
this.y = svg.getPointAtLength(counter*straightLength).y;
}
counter+=0.0003;//так картинки передвигаются по path друг на друге, как организовать нечто вроде "паровозика"? Перебрал много вариантов в цикле, но ничего не вышло..
context.beginPath();
context.globalCompositeOperation = "source-over";
context.save();
context.translate(this.x, this.y);
context.rotate(Gangle * TO_RADIANS);
var image = new Image();
image.src = 'img/bag.png';
context.drawImage(image,20, -20, 40, 40);
context.restore();
angle+=0.1;
}
};
for (var i = 0; i < 10; i++) {
var particle = new Particle();
particles.push(particle);
}
function animate() {
context.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particles.length; i++) {
particles[i].move();
}
requestAnimFrame(animate);
}
animate();
Как организовать движение картинок по path друг за другом
Для решения этой задачи необходимо нарисовать path в векторном редакторе или вручную.
Движение вдоль этого пути реализуется командой
С привязкой объектов движения к пути посредством ID этого пути с помощью команды
`
Начало движения при наведении на кнопку "Start" begin="startButton.mouseover"
Окончание анимации при наведении на кнопку "Stop" end="stopGreen.mouseover"
Далее добавляются еще два подобных блока кода для двух других объектов движения.
Для реализации движения друг за другом нескольких объектов, задается пауза до начала анимации для второго и третьего шарика. begin="startButton.mouseover+0.25s"
Необязательные украшательства:
Добавлены маркеры для указания направления движения, паттерн фона и блок радиокнопок остановки объектов движения.
Ниже пример кода:
Анимация адаптивна, пробуйте изменять размер окна браузера.
Вариант #2
Объекты движения заменены на более сложные (ведьмы на метлах)
Изменена траектория движения (заменяем патч
Начало анимации при наведении на кнопку "Start"
Приостановка объектов анимации при наведении на соответствующую радиокнопку.
Красным это видео. Черным это размер экрана телефона. Я использую SurfaceView.
Как мне подогнать видео под размер экрана. орентировываясь по ширине Экрана телефона.
Сохраняю пропорции.
В ImageView все просто. Добавил картинку и она сама с сохранением пропорций отображается.
Если вы хотите использовать именно SurfaceView, то стоит сделать так:
Например у нас есть такая разметка:
Подключаем необходимые нам элементы:
surfaceViewFrame = (SurfaceView) findViewById(R.id.surfaceViewFrame);
player = new MediaPlayer();
player.setDisplay(holder);
А теперь немного расчетов добавим в ваш MediaPlayer в onPreparedListener и пересчитаем высоту и ширину видео фрагмента в соответствии с текущими размерами экрана, избежав растягивания.
player.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared (MediaPlayer mp){
int videoWidth = player.getVideoWidth();
int videoHeight = player.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = surfaceViewFrame.getLayoutParams();
if (videoProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
} else {
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
}
surfaceViewFrame.setLayoutParams(lp);
if (!player.isPlaying()) {
player.start();
}
}
});
Недавно читал статьи по созданию собственных тегов в HTML и натолкнулся на неизвестный мне атрибут is. Статья: https://learn.javascript.ru/...
Зачем этот атрибут? Можно ли его использовать, к примеру, для вставки иконок (..)? Насколько он валиден в старых браузерах?
is является частью W3C спецификации и используется для создания пользовательских элементов HTML с пользовательским поведением.
В частности, is используется при расширении свойств встроенного элемента, например ,